Python并发机制(二)——多线程
2016-11-22 21:35
671 查看
Python并发机制(二)——多线程
实例化threading.Thread()
import threading,time def fn(n): print n print str(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime())) def main(): tpool = [] for i in range(10): t = threading.Thread(target=fn,args=(0,)) tpool.append(t) for t in tpool: t.start() for t in tpool: threading.Thread.join(t) if __main__ == '__name__': main()
运行结果如下:
1 1 2016-11-22 01:22:29 2016-11-22 01:22:29 11 2016-11-22 01:22:29 2016-11-22 01:22:29 1 2016-11-22 01:22:29 1 2016-11-22 01:22:29 1 2016-11-22 01:22:29 1 12016-11-22 01:22:29 1 2016-11-22 01:22:29 2016-11-22 01:22:29
自定义线程类的实例化
import threading,time class myThread(threading.Thread): def __init__(self,n): threading.Thread.__init__(self) self.n = n def fn(self): print self.n print str(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime())) def run(self): self.fn() def main(): tpool = [] for i in range(10): tpool.append(myThread(1)) for t in tpool: t.start() for t in tpool: t.join() if __name__ == '__main__': main()
运行结果如下:
1 2016-11-22 01:46:36 1 12016-11-22 01:46:36 2016-11-22 01:46:36 1 2016-11-22 01:46:36 1 1 2016-11-22 01:46:36 2016-11-22 01:46:36 1 2016-11-22 01:46:36 1 2016-11-22 01:46:36 1 2016-11-22 01:46:36 1 2016-11-22 01:46:36
使用multiprocesssing.dummy执行多线程任务
#coding=utf-8 import urllib2 import time from multiprocesssing.dummy import Pool import threading from multiprocesssing import Pool as PPool urls = [ 'http://www.python.org', 'http://www.python.org/about/', 'http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html', 'http://www.python.org/doc/', 'http://www.python.org/download/', 'http://www.python.org/getit/', 'http://www.python.org/community/', 'https://wiki.python.org/moin/', 'http://planet.python.org/', 'https://wiki.python.org/moin/LocalUserGroups', 'http://www.python.org/psf/', 'http://docs.python.org/devguide/', 'http://www.python.org', 'http://www.python.org/about/', 'http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html', 'http://www.python.org/doc/', 'http://www.python.org/download/', 'http://www.python.org/getit/', 'http://www.python.org/community/', 'https://wiki.python.org/moin/', 'http://planet.python.org/', 'https://wiki.python.org/moin/LocalUserGroups', 'http://www.python.org/psf/', 'http://docs.python.org/devguide/', ] #单线程时间 start = time.time() result = map(urllib2.urlopen,urls) t1 = time.time() - start print "单线程时间:",t1 #4线程时间 time.sleep(1) start = time.time() pool = Pool(4) result = pool.map(urllib2.urlopen,urls) pool.close() pool.join() t4 = time.time() - start print "4线程时间:",t4 #8线程时间 time.sleep(1) start = time.time() pool = Pool(12) result = pool.map(urllib2.urlopen,urls) pool.close() pool.join() t8 = time.time() - start print "12线程时间:",t8 #threading模块4线程 time.sleep(1) start = time.time() t = [] for i in range(4): t.append(threading.Thread(target=map,args=(urllib2.urlopen,urls[i*3:i*3+3]))) for th in t: th.start() for th in t: th.join() t = time.time() - start print "threading模块4线程:",t #4进程 time.sleep(1) start = time.time() pool = PPool(processes=4) #注意加_async,非阻塞版本 results = pool.map_async(urllib2.urlopen,urls) pool.close() pool.join() t = time.time() - start print "4进程:",t
运行结果如下:
单线程时间: 23.5617449284 4线程时间: 5.81678104401 12线程时间: 2.70931982994 threading模块4线程: 4.12135195732 4进程: 5.78697896004
注意:受GIL机制(如下)影响的多线程实质上是交替单线程执行,利用multiproceessing. dummy.Pool实例化的线程池能实现并发,类似于进程池,如果将它们分为两类,则第一类更有利于IO密集型程序(如上例偏IO),第二类更有利于CPU密集型程序
python(CPython)全局锁(GIL)机制
首先需要明确的一点是 GIL 并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。就好比C++是一套语言(语法)标准,但是可以用不同的编译器来编译成可执行代码。有名的编译器例如GCC,INTEL C++,Visual C++等。Python也一样,同样一段代码可以通过CPython,PyPy,Psyco等不同的Python执行环境来执行。像其中的JPython就没有GIL。然而因为CPython是大部分环境下默认的Python执行环境。所以在很多人的概念里CPython就是Python,也就想当然的把 GIL 归结为Python语言的缺陷。所以这里要先明确一点:GIL并不是Python的特性,Python完全可以不依赖于GIL因为Python的线程虽然是真正的线程,但解释器执行代码时,有一个GIL锁:Global Interpreter Lock,任何Python线程执行前,必须先获得GIL锁,然后,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行。这个GIL全局锁实际上把所有线程的执行代码都给上了锁,所以,多线程在Python中只能交替执行,即使100个线程跑在100核CPU上,也只能用到1个核。
多个线程如果共享一个变量,它们都有可能对变量进行修改,但高级语言的一条语句在CPU执行时是若干步,即使一个简单的计算common = common + 1也分为至少两步:
1. 求和common和1并将值转存到一个临时变量
2. 将临时变量值赋给common
由于线程是交替执行的,所以循环次数足够多时可能出现一个线程过程中执行另一个线程的第一步或第二步,如下:
import time,threading common = 0 def change(n): global common for i in range(100000): common = common + n common = common - n t1 = threading.Thread(target=change,args=(5,)) t2 = threading.Thread(target=change,args=(8,)) t1.start() t2.start() t1.join() t2.join() print common
运行结果如下:
261
所以我们运用线程锁(thrading.Lock())
import time,threading common = 0 lock = threading.Lock() def change(n): global common for i in range(100000): lock.acquire() try: common = common + n common = common - n #一定会释放锁 finally: lock.release() t1 = threading.Thread(target=change,args=(5,)) t2 = threading.Thread(target=change,args=(8,)) t1.start() t2.start() t1.join() t2.join() print common
运行结果为0
GIL解决了线程间数据一致性和状态同步的困难,但无疑大多数情况下它是低效的,但当大家开始抱怨并试图去拆分和去除GIL的时候,却发现大量库代码开发者已经重度依赖GIL而非常难以去除了。所以GIL的现存更多的是历史原因.
相关文章推荐
- 用同步机制解决多线程并发所产生的问题
- python中多线程调度机制以及GIL
- python多线程机制
- android多线程并发协调semaphore机制
- Python 用队列实现多线程并发
- 多线程_并发访问_锁机制_servelt
- 基于python多线程实现Linux任务并发执行
- 【Python之旅】第五篇(三):Python Socket多线程并发
- Python的多线程性能问题和并发问题
- “死锁” 与 python多线程之threading模块下的锁机制
- 《python源码剖析》笔记 python多线程机制
- python3.4多线程实现同步的四种方式(锁机制、条件变量、信号量和同步队列)
- 多线程并发编程之原子变量与非阻塞同步机制
- Python GIL 多线程机制 (C source code)
- Python 多线程教程:并发与并行
- python并发的痛——多线程
- Python 并发编程之使用多线程和多处理器
- Python 多线程教程:并发与并行
- Java中实现多线程并发的几种安全机制
- python实现多线程的方式及多条命令并发执行