python 多进程使用总结
python中的多进程主要使用到 multiprocessing 这个库。这个库在使用 multiprocessing.Manager().Queue时会出问题,建议大家升级到高版本python,如2.7.11,可具体参考《python版本升级》。
python使用线程池可参考《python线程池实现》
一、多进程使用
1、linux下可使用 fork 函数
#!/bin/env python
import os print 'Process (%s) start...' % os.getpid()
pid = os.fork()
if pid==0:
print 'I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid())
os._exit(1)
else:
print 'I (%s) just created a child process (%s).' % (os.getpid(), pid)
输出
Process (22246) start...
I (22246) just created a child process (22247).
I am child process (22247) and my parent is 22246.
2、使用 multiprocessing
#!/bin/env python
from multiprocessing import Process
import os
import time def run_proc(name):
time.sleep(3)
print 'Run child process %s (%s)...' % (name, os.getpid()) if __name__=='__main__':
print 'Parent process %s.' % os.getpid()
processes = list()
for i in range(5):
p = Process(target=run_proc, args=('test',))
print 'Process will start.'
p.start()
processes.append(p) for p in processes:
p.join()
print 'Process end.'
输出
Parent process 38140.
Process will start.
Process will start.
Process will start.
Process will start.
Process will start.
Run child process test (38141)...
Run child process test (38142)...
Run child process test (38143)...
Run child process test (38145)...
Run child process test (38144)...
Process end. real 0m3.028s
user 0m0.021s
sys 0m0.004s
二、进程池
1、使用 multiprocessing.Pool 非阻塞
#!/bin/env python import multiprocessing
import time def func(msg):
print "msg:", msg
time.sleep(3)
print "end" if __name__ == "__main__":
pool = multiprocessing.Pool(processes = 3)
for i in xrange(3):
msg = "hello %d" %(i)
pool.apply_async(func, (msg, )) print "Mark~ Mark~ Mark~~~~~~~~~~~~~~~~~~~~~~"
pool.close()
pool.join() # behind close() or terminate()
print "Sub-process(es) done."
运行结果
Mark~ Mark~ Mark~~~~~~~~~~~~~~~~~~~~~~
msg: hello 0
msg: hello 1
msg: hello 2
end
end
end
Sub-process(es) done. real 0m3.493s
user 0m0.056s
sys 0m0.022s
2、使用 multiprocessing.Pool 阻塞版本
#!/bin/env python import multiprocessing
import time def func(msg):
print "msg:", msg
time.sleep(3)
print "end" if __name__ == "__main__":
pool = multiprocessing.Pool(processes = 3)
for i in xrange(3):
msg = "hello %d" %(i)
pool.apply(func, (msg, )) print "Mark~ Mark~ Mark~~~~~~~~~~~~~~~~~~~~~~"
pool.close()
pool.join() # behind close() or terminate()
print "Sub-process(es) done."
运行结果
msg: hello 0
end
msg: hello 1
end
msg: hello 2
end
Mark~ Mark~ Mark~~~~~~~~~~~~~~~~~~~~~~
Sub-process(es) done. real 0m9.061s
user 0m0.036s
sys 0m0.019s
区别主要是 apply_async和 apply函数,前者是非阻塞的,后者是阻塞。可以看出运行时间相差的倍数正是进程池数量
3、使用 multiprocessing.Pool 并关注结果
import multiprocessing
import time def func(msg):
print "msg:", msg
time.sleep(3)
print "end"
return "done" + msg if __name__ == "__main__":
pool = multiprocessing.Pool(processes=4)
result = []
for i in xrange(3):
msg = "hello %d" %(i)
result.append(pool.apply_async(func, (msg, )))
pool.close()
pool.join()
for res in result:
print ":::", res.get()
print "Sub-process(es) done."
运行结果
msg: hello 0
msg: hello 1
msg: hello 2
end
end
end
::: donehello 0
::: donehello 1
::: donehello 2
Sub-process(es) done. real 0m3.526s
user 0m0.054s
sys 0m0.024s
4、在类中使用 multiprocessing.Pool
类中使用进程池会一般会出现错误
PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed
这个提示是因为 multiprocessing.Pool中使用了Queue通信,所有进入队列的数据必须可序列化(picklable),包括自定义类实例等。如下:
#!/bin/env python import multiprocessing class SomeClass(object):
def __init__(self):
pass def f(self, x):
return x*x def go(self):
pool = multiprocessing.Pool(processes=4)
#result = pool.apply_async(self.f, [10])
#print result.get(timeout=1)
print pool.map(self.f, range(10)) SomeClass().go()
运行提示
Traceback (most recent call last):
File "4.py", line 18, in <module>
SomeClass().go()
File "4.py", line 16, in go
print pool.map(self.f, range(10))
File "/usr/local/lib/python2.7/multiprocessing/pool.py", line 251, in map
return self.map_async(func, iterable, chunksize).get()
File "/usr/local/lib/python2.7/multiprocessing/pool.py", line 567, in get
raise self._value
cPickle.PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed
解决如下:(1)
#!/bin/env python
import multiprocessing def func(x):
return x*x class SomeClass(object):
def __init__(self,func):
self.f = func def go(self):
pool = multiprocessing.Pool(processes=4)
#result = pool.apply_async(self.f, [10])
#print result.get(timeout=1)
print pool.map(self.f, range(10)) SomeClass(func).go()
输出结果:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
(2)一般情况下我们如果在类中写好了处理逻辑,想要尽可能减少代码变动则可以使用下面方法
#!/bin/env python import multiprocessing class SomeClass(object):
def __init__(self):
pass def f(self, x):
return x*x def go(self):
result = list()
pool = multiprocessing.Pool(processes=4)
for i in range(10):
result.append(pool.apply_async(func, [self, i]))
pool.close()
pool.join()
for res in result:
print res.get(timeout=1) def func(client, x):
return client.f(x) SomeClass().go()
输出结果:
0
1
4
9
16
25
36
49
64
81
使用(2)的解决方法需要注意,如果SomeClass实例中有包含任何不可序列化的数据则会一直报错,一般是到res.get()报错,这时候你就要重新查看代码是否有不可序列化的变量了。如果有的话可以更改成全局变量解决。
三、多进程中使用线程池
有一种情景下需要使用到多进程和多线程:在CPU密集型的情况下一个ip的处理速度是0.04秒前后,单线程运行的时间大概是3m32s,单个CPU使用率100%;使用进程池(size=10)时间大概是6m50s,其中只有1个进程的CPU使用率达到90%,其他均是在30%左右;使用线程池(size=10)时间大概是4m39s,单个CPU使用率100%
可以看出使用多进程在这时候并不占优势,反而更慢。因为进程间的切换消耗了大部分资源和时间,而一个ip只需要0.04秒。而使用线程池由于只能利用单核CPU,则再怎么加大线程数量都没法提升速度,所以这时候应该使用多进程加多线程结合。
def run(self):
self.getData()
ipNums = len(self.ipInfo)
step = ipNums / multiprocessing.cpu_count()
ipList = list()
i = 0
j = 1
processList = list()
for ip in self.ipInfo:
ipList.append(ip)
i += 1
if i == step * j or i == ipNums:
j += 1
def innerRun():
wm = Pool.ThreadPool(CONF.POOL_SIZE)
for myIp in ipList:
wm.addJob(self.handleOne, myIp)
wm.waitForComplete()
process = multiprocessing.Process(target=innerRun)
process.start()
processList.append(process)
ipList = list()
for process in processList:
process.join()
机器有8个CPU,则使用8个进程加线程池,速度提升到35s,8个CPU的利用率均在50%左右,机器平均CPU75%左右。
四、多进程间通信
个人使用的比较多的是队列和共享内存。需要注意的是队列中Queue.Queue是线程安全的,但并不是进程安全,所以多进程一般使用线程、进程安全的multiprocessing.Queue(),而使用这个Queue如果数据量太大会导致进程莫名卡住(绝壁大坑来的),需要不断地消费。
The Queue class is a near clone of Queue.Queue. For example:
from multiprocessing import Process, Queue def f(q):
q.put([42, None, 'hello']) if __name__ == '__main__':
q = Queue()
p = Process(target=f, args=(q,))
p.start()
print q.get() # prints "[42, None, 'hello']"
p.join()
Queues are thread and process safe.
测试卡住的程序如下:
#!/bin/env python
from multiprocessing import Process, Queue class A(object):
def __init__(self):
pass
def r(self):
def f(q):
import time
time.sleep(1)
s = 2000 * 'ss' # 不卡不卡不卡
# s = 20000 * 'ss' # 卡住卡住卡住
q.put(['hello', s])
print "q.put(['hello', s])"
q = Queue(maxsize=0)
pL = list()
for i in range(10):
p = Process(target=f, args=(q,))
p.start()
pL.append(p)
for p in pL:
p.join()
print len(q.get()) if __name__ == '__main__':
A().r()
共享内存使用的一般是multiprocessing.Manager().Array/list/value/dict等。
其他的通信方式特别是分布式多进程可学习 廖雪峰官方网站 http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386832973658c780d8bfa4c6406f83b2b3097aed5df6000
python 多进程使用总结的更多相关文章
- Python多进程编程
转自:Python多进程编程 阅读目录 1. Process 2. Lock 3. Semaphore 4. Event 5. Queue 6. Pipe 7. Pool 序. multiproces ...
- Python多进程(1)——subprocess与Popen()
Python多进程方面涉及的模块主要包括: subprocess:可以在当前程序中执行其他程序或命令: mmap:提供一种基于内存的进程间通信机制: multiprocessing:提供支持多处理器技 ...
- Python多进程使用
[Python之旅]第六篇(六):Python多进程使用 香飘叶子 2016-05-10 10:57:50 浏览190 评论0 python 多进程 多进程通信 摘要: 关于进程与线程的对比, ...
- python多进程断点续传分片下载器
python多进程断点续传分片下载器 标签:python 下载器 多进程 因为爬虫要用到下载器,但是直接用urllib下载很慢,所以找了很久终于找到一个让我欣喜的下载器.他能够断点续传分片下载,极大提 ...
- Python多进程multiprocessing使用示例
mutilprocess简介 像线程一样管理进程,这个是mutilprocess的核心,他与threading很是相像,对多核CPU的利用率会比threading好的多. import multipr ...
- Python多进程并发(multiprocessing)用法实例详解
http://www.jb51.net/article/67116.htm 本文实例讲述了Python多进程并发(multiprocessing)用法.分享给大家供大家参考.具体分析如下: 由于Pyt ...
- python 多进程开发与多线程开发
转自: http://tchuairen.blog.51cto.com/3848118/1720965 博文作者参考的博文: 博文1 博文2 我们先来了解什么是进程? 程序并不能单独运行,只有将程 ...
- Python多进程----从入门到放弃
Python多进程 (所有只写如何起多进程跑数据,多进程数据汇总处理不提的都是耍流氓,恩,就这么任性) (1)进程间数据问题,因为多进程是完全copy出的子进程,具有独立的单元,数据存储就是问题了 ( ...
- day-4 python多进程编程知识点汇总
1. python多进程简介 由于Python设计的限制(我说的是咱们常用的CPython).最多只能用满1个CPU核心.Python提供了非常好用的多进程包multiprocessing,他提供了一 ...
- python 多进程 logging:ConcurrentLogHandler
python 多进程 logging:ConcurrentLogHandler python的logging模块RotatingFileHandler仅仅是线程安全的,如果多进程多线程使用,推荐 Co ...
随机推荐
- 安卓与IOS移动段浏览器视频与音频的问题与总结
1. 安卓.苹果移动浏览器上都不支持html5的视频与音频自动播放 2. 安卓.苹果移动浏览器要支持播放,前提是必须是用户触发的事件 3. 针对这个特殊的问题,代码需要在用户进来第一次屏幕触发中,去创 ...
- 设计模式(九): 从醋溜土豆丝和清炒苦瓜中来学习"模板方法模式"(Template Method Pattern)
今天是五.四青年节,祝大家节日快乐.看着今天这标题就有食欲,夏天到了,醋溜土豆丝和清炒苦瓜适合夏天吃,好吃不上火.这两道菜大部分人都应该吃过,特别是醋溜土豆丝,作为“鲁菜”的代表作之一更是为大众所熟知 ...
- ASP.NET Core 中文文档 第二章 指南(2)用 Visual Studio 和 ASP.NET Core MVC 创建首个 Web API
原文:Building Your First Web API with ASP.NET Core MVC and Visual Studio 作者:Mike Wasson 和 Rick Anderso ...
- ASP.NET Core 中文文档 第三章 原理(12)托管
原文:Hosting 作者:Steve Smith 翻译:娄宇(Lyrics) 校对:何镇汐.许登洋(Seay) 为了运行 ASP.NET Core 应用程序,你需要使用 WebHostBuilder ...
- 编写高质量代码:改善Java程序的151个建议(第4章:字符串___建议56~59)
建议56:自由选择字符串拼接方法 对一个字符串拼接有三种方法:加号.concat方法及StringBuilder(或StringBuffer ,由于StringBuffer的方法与StringBuil ...
- scikit-learn一般实例之四:使用管道和GridSearchCV选择降维
本例构建一个管道来进行降维和预测的工作:先降维,接着通过支持向量分类器进行预测.本例将演示与在网格搜索过程进行单变量特征选择相比,怎样使用GrideSearchCV和管道来优化单一的CV跑无监督的PC ...
- 在基于MVC的Web项目中使用Web API和直接连接两种方式混合式接入
在我之前介绍的混合式开发框架中,其界面是基于Winform的实现方式,后台使用Web API.WCF服务以及直接连接数据库的几种方式混合式接入,在Web项目中我们也可以采用这种方式实现混合式的接入方式 ...
- [Q&A] C1DataGrid 奇葩的 BeginNewRow() 方法
一.前言 用户千千万,自然需求就千奇百怪都有,某天有人提了这样一个需求: 某个 C1DataGrid 在 ScrollViewer 的底部(使纵向滚动条显示出来),然后当该 C1DataGrid 增加 ...
- js正则表达式校验正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?$
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 织梦cms常用标签
dedecms简介:织梦内容管理系统(DedeCms) 以简单.实用.开源而闻名,是国内知名的PHP开源网站管理系统,也是使用用户较多的PHP类CMS系统,在经历多年的发展,目前的版本无论在功能,还是 ...