之前在一篇文章中写过,有关于Python线程的问题:
是枝裕和:内:用python多线程同时处理大量文件zhuanlan.zhihu.com当然我的写的文章都是面对于一些初学者和python代码实战运用方面,对原理不做过多的解释,但是在python语言中,请记住这句话
由于GIL(全局解释器)的存在,该机制限制每个python进程中有且只有一个线程同时运行,也就是说即使写了threading,也于事无补,cpu只是在多个thread之间来回跳而已,并没有并发执行这些thread。
所以以后要写并发机制,还得用多进程multiprocessing模块
举个易于观察的实例,我在linux环境下分别用多线程和进程爬取大量网站的数据:
很显然,python对于大量文件的处理,采用多进程才是正确的处理方式。
废话说完,我们来科普一下python多进程模块的基本用法
先看一段简单的代码:
我们定义一个数组L,里面有4个人的名字;一个函数function,函数function分别打印:变量name,变量的pid,休眠1s后打印函数执行完毕的时间
import time
from multiprocessing import Pool
import os
L=["小刘","小张","小李","小迪"]
def function(name):
print(name,os.getpid(),function)
time.sleep(1)
print(time.ctime())
return
OK,先使用简单的for循环运行一下:
for name in L:
function(name)
显示结果如下:很显然函数的进程,内存地址都是一样的,运行时间也差了1s。即同一个函数传不同的参数每隔一秒运行一次,这不用多说了吧是。
现在我们不考虑进程间的通信,数据共享,锁问题等等,如何最简单有效对大量的csv文件实现多进程并发执行呢?我相信段代码能解决90%以上文件处理的问题
if __name__=="__main__":
p=Pool(4)
for i in L:
p.apply_async(function,args=(i,))
p.close()
p.join()
print("所有进程执行完毕")
解释一下:
if __name__=="__main__":
多进程在windows运行必须添加这段代码。
(通常情况下这段代码的意思为:当.py文件被直接运行时,if __name__ == '__main__'之下的代码块将被运行;当.py文件以模块形式被导入时,if __name__ == '__main__'之下的代码块不被运行。)
p=Pool(4)
for i in L:
p.apply_async(function,args=(i,))
创建一个4个进程的进程池,并用apply_async (异步非阻塞)的方式执行函数
你既然想并发就不要用apply的方式,反正我没用过。
后面的参数(function=所要执行的函数,args=()所要执行的函数中的参数)
记得函数不用加(),以及参数后面最后的逗号
然后将进程池
p.close()
p.join()
p.join()的意思是等待所有结果执行完毕,会等待所有子进程执行完毕
注意:close必须在join前调用
自己看结果吧~
多进程的运用还是很广泛的,比如你要处理1000个CSV文件,你用遍历一个个的运行,cpu利用率5%,但是如果你开16个进程 p=Pool(16)(看内核个数),你就可以并发处理16个文件,效率提高了16倍...
比如吧
我想看看我的“/2014_test/”文件夹下的每个csv文件有多少行数据,采用多进程,很快就能出来了
import time
import os
import csv
from multiprocessing import Pool
path = "/2014_test/"
files = os.listdir(path)
def function(i):
list=[]
with open(path+str(i),encoding="utf-8") as f :
reader=csv.reader(f)
for row in reader:
list.append(row)
print(len(list))
print(time.ctime())
if __name__=="__main__":
p=Pool(4)
for i in files:
p.apply_async(function,args=(i,))
p.close()
p.join()
if __name__ == '__main__':
for i in files:
l=[]
p=Process(target=analyze_url,args=("/opt/linux_work/avaurl/2016/2016_5/" + i, i, "/opt/linux_work/parse/text/2016/2016_5/", "/opt/linux_work/parse/unparse/",))
l.append(p)
for p in l:
p.start ()
溜了溜了