赞
踩
一、多线程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()
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()
如果想所有的都运行完了之后再显示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()
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()
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)
如果你成功运行整套程序, 你大概会有这样的输出. 我们的运算结果没错, 所以程序 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()
可以看出,打印的结果非常混乱
(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()
使用 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() '''''
(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)
(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)
(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()
运行结果:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
4
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。