当前位置:   article > 正文

多线程Threading和多进程Multiprocessing_多进程multiprocessing知识梳理(对比多线程threading)

多进程multiprocessing知识梳理(对比多线程threading)

一、多线程Threading
1、Threading分配python分批量在同一时间去做很多事情,减小了计算时间。
2、添加线程

# -*- coding: utf-8 -*-
import threading
def thread_job():
    print ('this is an thread,number is %s'%threading.current_thread())
def main():
    add_thread=threading.Thread(target=thread_job)#添加线程,target=这个线程的目标
    add_thread.start()#运行
    # print(threading.active_count())#算一下现在有多少激活了的threading
    # print(threading.enumerate())#看一下激活的是哪些threading
    # print(threading.current_thread())#看现在运行的是哪个线程
if __name__ == '__main__':
    main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

3、join功能

# -*- coding: utf-8 -*-
import threading
import time
def thread_job():
    print ('T1 start\n')
    for i in range(10):
        time.sleep(0.1)
    print ('T1 finish\n')
def main():
    add_thread=threading.Thread(target=thread_job,name='T1')#添加线程,target=这个线程的目标
    add_thread.start()#运行
    print ('all done\n')
    # print(threading.active_count())#算一下现在有多少激活了的threading
    # print(threading.enumerate())#看一下激活的是哪些threading
    # print(threading.current_thread())#看现在运行的是哪个线程
if __name__ == '__main__':
    main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在这里插入图片描述
如果想所有的都运行完了之后再显示all down,就要添加join

# -*- coding: utf-8 -*-
import threading
import time
def thread_job():
    print ('T1 start\n')
    for i in range(10):
        time.sleep(0.1)
    print ('T1 finish\n')
def T2_job():
    print ('T2 start\n')
    print ('T2 finish\n')
def main():
    add_thread=threading.Thread(target=thread_job,name='T1')#添加线程,target=这个线程的目标
    thread2=threading.Thread(target=T2_job,name='T2')
    add_thread.start()#运行
    thread2.start()
    add_thread.join()#保证下边的程序要在T1运行结束后运行
    thread2.join()
    print ('all done\n')
    # print(threading.active_count())#算一下现在有多少激活了的threading
    # print(threading.enumerate())#看一下激活的是哪些threading
    # print(threading.current_thread())#看现在运行的是哪个线程
if __name__ == '__main__':
    main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

4、储存进程结果 Queue
多线程主要实现的结果是没有返回值的,所以要把运算出来的结果放入队列当中,对每一个线程的队列到主线程中拿出来,进行计算。

# -*- coding: utf-8 -*-
# View more python learning tutorial on my Youtube and Youku channel!!!

# Youtube video tutorial: https://www.youtube.com/channel/UCdyjiB5H8Pu7aDTNVXTTpcg
# Youku video tutorial: http://i.youku.com/pythontutorial

import threading
import time
from Queue import Queue

def job(l,q):
    for i in range(len(l)):
        l[i] = l[i]**2
    q.put(l)

def multithreading():
    q = Queue()#在q中放返回值替代return
    threads = []#所有的线程放到这个列表中
    data = [[1,2,3],[3,4,5],[4,4,4],[5,5,5]]
    for i in range(4):
        t = threading.Thread(target=job, args=(data[i], q))#添加线程#job不用加括号,只是索引
        t.start()#运行线程
        threads.append(t)
    for thread in threads:
        thread.join()
    results = []
    for _ in range(4):
          results.append(q.get())
    print(results)

if __name__ == '__main__':
    multithreading()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

5、GIL 不一定有效率
尽管Python完全支持多线程编程, 但是解释器的C语言实现部分在完全并行执行时并不是线程安全的。 实际上,解释器被一个全局解释器锁保护着,它确保任何时候都只有一个Python线程执行。 GIL最大的问题就是Python的多线程程序并不能利用多核CPU的优势 (比如一个使用了多个线程的计算密集型程序只会在一个单CPU上面运行)。

# -*- coding: utf-8 -*-
import threading
from Queue import Queue
import copy
import time

def job(l, q):
    res = sum(l)
    q.put(res)

def multithreading(l):
    q = Queue()
    threads = []
    for i in range(4):
        t = threading.Thread(target=job, args=(copy.copy(l), q), name='T%i' % i)
        t.start()
        threads.append(t)
    [t.join() for t in threads]
    total = 0
    for _ in range(4):
        total += q.get()
    print(total)

def normal(l):
    total = sum(l)
    print(total)

if __name__ == '__main__':
    l = list(range(1000000))
    s_t = time.time()
    normal(l*4)
    print('normal: ',time.time()-s_t)
    s_t = time.time()
    multithreading(l)
    print('multithreading: ', time.time()-s_t)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

如果你成功运行整套程序, 你大概会有这样的输出. 我们的运算结果没错, 所以程序 threading 和 Normal 运行了一样多次的运算. 但是我们发现 threading 却没有快多少, 按理来说, 我们预期会要快3-4倍, 因为有建立4个线程, 但是并没有. 这就是其中的 GIL 在作怪.python多线程对IO密集型有用,对计算密集型没有用。
6、线程锁 Lock

(1)不适用LOCK

import threading

def job1():
    global A
    for i in range(10):
        A+=1
        print('job1',A)

def job2():
    global A
    for i in range(10):
        A+=10
        print('job2',A)

if __name__== '__main__':
    lock=threading.Lock()
    A=0
    t1=threading.Thread(target=job1)
    t2=threading.Thread(target=job2)
    t1.start()
    t2.start()
    t1.join()
    t2.join()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

在这里插入图片描述
可以看出,打印的结果非常混乱
(2)使用lock

import threading

def job1():
    global A,lock#函数加锁
    lock.acquire()
    for i in range(10):
        A+=1
        print('job1',A)
    lock.release()#函数加锁

def job2():
    global A,lock
    lock.acquire()
    for i in range(10):
        A+=10
        print('job2',A)
    lock.release()

if __name__== '__main__':
    lock=threading.Lock()#主函数定义一个lock
    A=0
    t1=threading.Thread(target=job1)
    t2=threading.Thread(target=job2)
    t1.start()
    t2.start()
    t1.join()
    t2.join()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

在这里插入图片描述
使用 Lock 的情况
lock在不同线程使用同一共享内存时,能够确保线程之间互不影响,使用lock的方法是, 在每个线程执行运算修改共享内存之前,执行lock.acquire()将共享内存上锁, 确保当前线程执行时,内存不会被其他线程访问,执行运算完毕后,使用lock.release()将锁打开, 保证其他的线程可以使用该共享内存。

二、多进程Multiprocessing
(1)添加进程Process

# -*- coding: utf-8 -*-
import multiprocessing as mp#导入进程标准模块

def job(a,d):#定义一个被线程和进程调用的函数
    print('aaaaa')

if __name__=='__main__':
    p1 = mp.Process(target=job,args=(1,2))#创建进程
    p1.start()#启动进程
    p1.join()#连接进程
#线程进程对比
'''''
import multiprocessing as mp
import threading as td

def job(a,d):
    print('aaaaa')

t1 = td.Thread(target=job,args=(1,2))
p1 = mp.Process(target=job,args=(1,2))
t1.start()
p1.start()
t1.join()
p1.join()
'''''
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

(2)存储进程输出Queue

# -*- coding: utf-8 -*-
#Queue的功能是将每个核或线程的运算结果放在队里中, 等到每个线程或核运行完毕后再从队列中取出结果, 继续加载运算。
#原因很简单, 多线程调用的函数不能有返回值, 所以使用Queue存储多个线程运算的结果
import multiprocessing as mp
#函数没有返回值
def job(q):
    res=0
    for i in range(1000):
        res+=i+i**2+i**3
    q.put(res)    #queue

if __name__=='__main__':
    q = mp.Queue()#定义多线程序列,用来储存结果
    #定义两个线程函数,用来处理同一个任务
    p1 = mp.Process(target=job,args=(q,))#args 的参数只要一个值的时候,参数后面需要加一个逗号,表示args是可迭代的,后面可能还有别的参数,不加逗号会出错
    p2 = mp.Process(target=job,args=(q,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    res1 = q.get()#输出
    res2 = q.get()#输出
    print(res1+res2)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

(3)效率对比:多进程 < 普通 < 多线程

# -*- coding: utf-8 -*-
# View more python learning tutorial on my Youtube and Youku channel!!!

# Youtube video tutorial: https://www.youtube.com/channel/UCdyjiB5H8Pu7aDTNVXTTpcg
# Youku video tutorial: http://i.youku.com/pythontutorial

import multiprocessing as mp
import threading as td
import time

def job(q):
    res = 0
    for i in range(1000000):
        res += i+i**2+i**3
    q.put(res) # queue
#多进程、多核
def multicore():
    q = mp.Queue()
    p1 = mp.Process(target=job, args=(q,))
    p2 = mp.Process(target=job, args=(q,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    res1 = q.get()
    res2 = q.get()
    print('multicore:' , res1+res2)

def normal():
    res = 0
    for _ in range(2):
        for i in range(1000000):
            res += i+i**2+i**3
    print('normal:', res)

def multithread():
    q = mp.Queue()
    t1 = td.Thread(target=job, args=(q,))#
    t2 = td.Thread(target=job, args=(q,))#
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    res1 = q.get()
    res2 = q.get()
    print('multithread:', res1+res2)

if __name__ == '__main__':
    st = time.time()
    normal()
    st1= time.time()
    print('normal time:', st1 - st)
    multithread()
    st2 = time.time()
    print('multithread time:', st2 - st1)
    multicore()
    print('multicore time:', time.time()-st2)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

(4)进程池
进程池就是我们将所要运行的东西,放到池子里,Python会自行解决多进程的问题。

# -*- coding: utf-8 -*-
import multiprocessing as mp

def job(x):
    return x*x

def multicore():
    #有了池子之后,就可以让池子对应某一个函数,我们向池子里丢数据,池子就会返回函数返回的值
    pool = mp.Pool(processes=2)#强调到底用几个核
    res = pool.map(job, range(10))#用map()获取结果,在map()中需要放入函数和需要迭代运算的值,然后它会自动分配给CPU核,返回结果
    print(res)
    res = pool.apply_async(job, (2,))#只能传递一个值,他只会放入一个核进行运算,但是传入值时要注意是可迭代的,所以传入值后需要加逗号
    print(res.get())
    multi_res =[pool.apply_async(job, (i,)) for i in range(10)]
    print([res.get() for res in multi_res])

if __name__ == '__main__':
    multicore()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

运行结果:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
4
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/151436
推荐阅读
相关标签
  

闽ICP备14008679号