您的位置:首页 > 编程语言 > Python开发

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: