Python 线程、进程和协程
2016-01-09 17:56
651 查看
#!/usr/bin/env python # -*- coding:utf-8 -*- from multiprocessing import Process, Array, RLock def Foo(lock,temp,i): """ 将第0个数加100 """ lock.acquire() temp[0] = 100+i for item in temp: print i,'----->',item lock.release() lock = RLock() temp = Array('i', [11, 22, 33, 44]) for i in range(20): p = Process(target=Foo,args=(lock,temp,i,)) p.start() 进程锁
进程锁
进程池
进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。
进程池中有两个方法:
apply
apply_async
#!/usr/bin/env python # -*- coding:utf-8 -*- from multiprocessing import Process,Pool import time def Foo(i): time.sleep(2) return i+100 def Bar(arg): print arg pool = Pool(5) #创建一个进程池 #print pool.apply(Foo,(1,))#去进程池里去申请一个进程去执行Foo方法 #print pool.apply_async(func =Foo, args=(1,)).get() for i in range(10): pool.apply_async(func=Foo, args=(i,),callback=Bar) print 'end' pool.close() pool.join()#进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。 ''' apply 主动的去执行 pool.apply_async(func=Foo, args=(i,),callback=Bar) 相当于异步,当申请一个线程之后,执行FOO方法就不管了,执行完之后就在执行callback ,当你执行完之后,在执行一个方法告诉我执行完了 callback 有个函数,这个函数就是操作的Foo函数的返回值! '''
线程和进程的操作是由程序触发系统接口,最后的执行者是系统;协程的操作则是程序员。
协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续)。协程,则只使用一个线程,在一个线程中规定某个代码块执行顺序。
协程的适用场景:当程序中存在大量不需要CPU的操作时(IO),适用于协程;
[b]greenlet[/b]
#!/usr/bin/env python # -*- coding:utf-8 -*- from greenlet import greenlet def test1(): print 12 gr2.switch()#切换到协程2执行 print 34 #2切回来之后,在这里和yield类似 gr2.switch() def test2(): print 56 gr1.switch()#上面执行了一句,在切换到协程1里去了 print 78 gr1 = greenlet(test1) #创建了一个协程 gr2 = greenlet(test2) gr1.switch() #执行test1 ''' 比I/O操作,如果10个I/O,我程序从上往下执行,如果同时发出去了10个I/O操作,那么返回的结果如果同时回来了2个 ,是不是就节省了很多时间? 如果一个线程里面I/O操作特别多,使用协程是不是就非常适用了! 如果一个线程访问URL通过协程来做,协程告诉它你去请求吧,然后继续执行,但是如果不用协程就得等待第一个请求完毕之后返回之后才 继续下一个请求。 协程:把一个线程分成了多个协程操作,每个协程做操作 多线程:是把每一个操作,分为多个线程做操作,但是python中,在同一时刻只能有一个线程操作,并且有上下文切换。但是如果上下文切换非常频繁的话 是非常耗时的,但对于协程切换就非常轻便了~
协程就是对线程的分片,上面的例子需要手动操作可能用处不是很大了解原理,看下面的例子:
上面的greenlet是需要认为的制定调度顺序的,所以又出了一个gevent他是对greenlet功能进行封装
import gevent def foo(): print('Running in foo') gevent.sleep(0) print('Explicit context switch to foo again') def bar(): print('Explicit context to bar') gevent.sleep(0) print('Implicit context switch back to bar') gevent.joinall([ gevent.spawn(foo), gevent.spawn(bar), ])
遇到IO操作自动切换:
from gevent import monkey; monkey.patch_all() import gevent import urllib2 def f(url): print('GET: %s' % url) resp = urllib2.urlopen(url) #当遇到I/O操作的时候就会调用协程操作,然后继续往下走,然后这个协程就卡在这里等待数据的返回 data = resp.read() print('%d bytes received from %s.' % (len(data), url)) gevent.joinall([ gevent.spawn(f, 'https://www.python.org/'), #这里的f是调用这个方法,第二个是调用方的参数 gevent.spawn(f, 'https://www.yahoo.com/'), gevent.spawn(f, 'https://github.com/'), ]) ''' gevent.spawn(f, 'https://www.python.org/'), #这里的f是调用这个方法,第二个是调用方的参数 当函数f里的代码遇到I/O操作的时候,函数就卡在哪里等待数据的返回,但是协程不会等待而是继续操作! '''
*
*
*
参考文档:http://www.cnblogs.com/wupeiqi/articles/5040827.html
http://www.cnblogs.com/luotianshuai/p/5111587.html
相关文章推荐
- numpy实用技巧(一)
- python文件处理方式
- python之线程学习
- python面向对象特性----mutable, immutable, 函数传参
- python crc计算器
- python新手笔记之python继承
- Python新手笔记之python迭代器遍历列表
- python新手笔记之包和模块的引入
- python新手笔记之python高级函数编程
- python学习――――模块subprocess
- Python Flask 开发环境搭建(Windows)
- ubuntu14.04 server python3.4 安装 numpy scipy matplotlib
- 使用python 提取网页的特定数据转
- python入门笔记(Day4)--map,reduce
- Python FTP 文件上传 例程
- ubuntu14.04 server python2.7 安装 numpy scipy matplotlib
- python运维笔记第一节
- ubuntu14.04 server python3 安装matplotlib失败及解决方法
- python大小写转换
- python文件中 `if __name__ == '__main__':` 的作用