__author__ = 'alex' #coding:utf-8 from multiprocessing import Process def foo(i): print (i) if __name__ == '__main__': for i in range(10): p = Process(target=foo,args=(i,)) p.start()
进程的数据默认不共享
#coding:utf-8 from multiprocessing import Process def foo(i,li): li.append(i) print ('li is ',li) # print (i) li = [] if __name__ == '__main__': for i in range(10): p = Process(target=foo,args=(i,li)) p.start()
输出结果:
li is [1] li is [0] li is [3] li is [2] li is [5] li is [7] li is [4] li is [6] li is [8] li is [9]
这个跟我们设想要的结果不一致,我们需要的是for循环中的数据一个个的被append到列表中去,这就涉及到了进程间的通信。
#coding:utf-8 from multiprocessing import Process from multiprocessing import queues import multiprocessing import time def foo(i,q): time.sleep(1) q.put(i) # time.sleep(1) print ('qsize is ',q.qsize()) # print (i) q = queues.Queue(ctx=multiprocessing) if __name__ == '__main__': for i in range(10): p = Process(target=foo,args=(i,q)) p.start()
1,使用multiprocessing模块中的queues类,可以实现进程间的通信,输出结果:
qsize is 1 qsize is 2 qsize is 3 qsize is 4 qsize is 5 qsize is 6 qsize is 7 qsize is 8 qsize is 10 qsize is 10
2,也可以利用python的Array来实现,Array较之list的不同在于,数组的元素位置都是在一起的,大小是事先分配好的。
#coding:utf-8 from multiprocessing import Process from multiprocessing import queues import multiprocessing import time from multiprocessing import Array def foo(i,arr): time.sleep(2) arr[i] = i # time.sleep(1) # print ('qsize is ',q.qsize()) # print (i) for item in arr: print (item) print ("===================") arr = Array('i',10) if __name__ == '__main__': for i in range(10): p = Process(target=foo,args=(i,arr)) p.start()
执行最终结果是:
0
1
2
3
4
5
6
7
8
9
但是因为线程之间无法确定哪个线程先执行完的(CPU的调度是随机的),所以刚开始的数据可能是无序的。
3,也可以使用一个特殊的dict()类来实现,但是下面的代码执行有问题,因为是用fork()的机制来产生进程的,所以在windows下面不支持,但是在Linux和MAC中是可以支持的,未测试!
进程间的通信使用的也是socket的方式来实现的,在下面的代码中,main函数里面sleep(2)了2秒,原因是主进程和子进程在通信过程中,如果子进程还没有执行完,但是子进程已经执行完退出了,那么子进程将不能进行消息的收发了,因而不能实现进程间通信了,如果把sleep的时间改到0.1秒,那么可以看到的结果是,有一部分的数据执行出来了,剩余的程序未执行完就报错了。
#coding:utf-8
from multiprocessing import Process
from multiprocessing import queues
import multiprocessing
import time
from multiprocessing import Array
from multiprocessing import Manager
manage = Manager()
dic = manage.dict()
def foo(i,dic):
dic[i] = i +100
print (dic.values())
if __name__ == '__main__':
for i in range(10):
p = Process(target=foo,args=(i,dic))
p.start()
time.sleep(2)
进程跟线程一样,操作同一份数据的时候也需要加锁:
from multiprocessing import Process,Array import time arr = Array('i',1) arr[0] = 10 def foo(arr): arr[0] -= 1 time.sleep(1) print (arr[0]) if __name__ == '__main__': for i in range(10): p = Process(target=foo,args=(arr,)) p.start()
因为添加了sleep(1),所以每次执行循环的时候,每个子进程都执行了一遍减一的操作,最终所有的输出结果都是0
0
0
0
0
0
0
0
0
0
0
因此,我们需要给进程加锁:
from multiprocessing import Process,Array import time from multiprocessing import RLock lk = RLock() arr = Array('i',1) arr[0] = 10 def foo(arr,lc): lc.acquire() arr[0] -= 1 time.sleep(1) print (arr[0]) lc.release() if __name__ == '__main__': for i in range(10): p = Process(target=foo,args=(arr,lk)) p.start()
执行结果:
9
8
7
6
5
4
3
2
1
0
进程锁:
from multiprocessing import Pool from multiprocessing import Process import time def foo(arg): time.sleep(1) print (arg) if __name__ == '__main__': p = Pool(5) for i in range(10): p.apply(func=foo,args=(i,))
执行结果,每隔一秒打印一个数值:
0
1
2
3
4
5
6
7
8
9
改成另外的写法:
from multiprocessing import Pool from multiprocessing import Process import time def foo(arg): time.sleep(1) print (arg) if __name__ == '__main__': p = Pool(5) for i in range(10): p.apply_async(func=foo,args=(i,)) p.close() p.join()
在执行join方法之前必须先执行close()或者terminate()方法。
执行结果:
0
1
2
3
4
5
6
7
8
9
如果用terminate方法改写:
from multiprocessing import Pool from multiprocessing import Process import time def foo(arg): time.sleep(1) print (arg) if __name__ == '__main__': p = Pool(5) for i in range(10): p.apply_async(func=foo,args=(i,)) time.sleep(2) p.terminate() # p.close() p.join()
执行结果:
0
1
2
3
4
terminate表示当前的子进程执行完毕就不执行了,close表示所有的进程都执行完毕之后才执行主进程。
协程是把一个线程分解了,成为多个“微线程”,实现IO操作,要实现协程,到导入greenlet模块。首先我们要安装这个模块。
我们看到,在python安装的时候,已经安装了pip模块和setuptools模块,现在我们需要利用pip3模块来安装。
pip3,easy_install命令都在C:UsersalexAppDataLocalProgramsPythonPython35Scripts这个目录下面,运行CMD到这个模块,然后执行
C:UsersalexAppDataLocalProgramsPythonPython35Scripts>pip3 install greenlet Collecting greenlet Downloading greenlet-0.4.10-cp35-cp35m-win_amd64.whl Installing collected packages: greenlet Successfully installed greenlet-0.4.10 You are using pip version 8.1.1, however version 8.1.2 is available. You should consider upgrading via the 'python -m pip install --upgrade pip' comm and.
可以看到开始的截图,我们已经安装成功了。通过help('modules')模块可以查看已经安装的模块。
greenlet模块
from greenlet import greenlet def test1(): print (12) gr2.switch() print (34) gr2.switch() def test2(): print (56) gr1.switch() print (78) gr1.switch() gr1 = greenlet(test1) gr2 = greenlet(test2) gr1.switch()
执行结果:
12 56 34 78
gevent模块
import gevent def foo(): print ("foo begin") gevent.sleep(0) print ("foo end") def bar(): print ("bar begin") gevent.sleep(0) print ("bar end") gevent.joinall([gevent.spawn(foo),gevent.spawn(bar)])
执行结果:
foo begin
bar begin
foo end
bar end
gevent的使用:
import gevent
from gevent import monkey;monkey.patch_all() #修改了原有的socket方法,当你发起请求的时候,默认socket不会告知程序执行完成与否,pathch_all方法会返回 #执行完成的通知 import requests import time def send(url): print("GET %s" %url) resp = requests.get(url) data = resp.text print ('%s has received by %s'%(len(data),url)) gevent.joinall([gevent.spawn(send,'https://www.python.org'), gevent.spawn(send,'http://www.baidu.com') ])
执行结果:
GET https://www.python.org
GET http://www.baidu.com
2381 has received by http://www.baidu.com
47412 has received by https://www.python.org