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 多进程使用总结的更多相关文章

  1. Python多进程编程

    转自:Python多进程编程 阅读目录 1. Process 2. Lock 3. Semaphore 4. Event 5. Queue 6. Pipe 7. Pool 序. multiproces ...

  2. Python多进程(1)——subprocess与Popen()

    Python多进程方面涉及的模块主要包括: subprocess:可以在当前程序中执行其他程序或命令: mmap:提供一种基于内存的进程间通信机制: multiprocessing:提供支持多处理器技 ...

  3. Python多进程使用

    [Python之旅]第六篇(六):Python多进程使用   香飘叶子 2016-05-10 10:57:50 浏览190 评论0 python 多进程 多进程通信 摘要:   关于进程与线程的对比, ...

  4. python多进程断点续传分片下载器

    python多进程断点续传分片下载器 标签:python 下载器 多进程 因为爬虫要用到下载器,但是直接用urllib下载很慢,所以找了很久终于找到一个让我欣喜的下载器.他能够断点续传分片下载,极大提 ...

  5. Python多进程multiprocessing使用示例

    mutilprocess简介 像线程一样管理进程,这个是mutilprocess的核心,他与threading很是相像,对多核CPU的利用率会比threading好的多. import multipr ...

  6. Python多进程并发(multiprocessing)用法实例详解

    http://www.jb51.net/article/67116.htm 本文实例讲述了Python多进程并发(multiprocessing)用法.分享给大家供大家参考.具体分析如下: 由于Pyt ...

  7. python 多进程开发与多线程开发

    转自: http://tchuairen.blog.51cto.com/3848118/1720965 博文作者参考的博文:  博文1  博文2 我们先来了解什么是进程? 程序并不能单独运行,只有将程 ...

  8. Python多进程----从入门到放弃

    Python多进程 (所有只写如何起多进程跑数据,多进程数据汇总处理不提的都是耍流氓,恩,就这么任性) (1)进程间数据问题,因为多进程是完全copy出的子进程,具有独立的单元,数据存储就是问题了 ( ...

  9. day-4 python多进程编程知识点汇总

    1. python多进程简介 由于Python设计的限制(我说的是咱们常用的CPython).最多只能用满1个CPU核心.Python提供了非常好用的多进程包multiprocessing,他提供了一 ...

  10. python 多进程 logging:ConcurrentLogHandler

    python 多进程 logging:ConcurrentLogHandler python的logging模块RotatingFileHandler仅仅是线程安全的,如果多进程多线程使用,推荐 Co ...

随机推荐

  1. HTML (超文本标记语言)

    <html> --开始标签 <head> 网页上的控制信息 <title>页面标题</title> </head> <body> ...

  2. ECMASCript2015 提案 stage-3的对象展开运算符

    看源码时看到如下的代码 export default { //通过mapActions将actions映射到methods里 methods: { ...mapActions([ 'updateSta ...

  3. UEditor编辑器使用示例

    1. UEditor下载 UEditor是由百度web前端研发部开发所见即所得富文本web编辑器,具有轻量,可定制,注重用户体验等特点,开源基于MIT协议,允许自由使用和修改代码. 下载链接:http ...

  4. PHP 高级编程(5/5) - SPL 数组重载

    ArrayAccess接口 ArrayAccess接口是对象的行为看起来像个数组,定义了四个方法.接口概要如下: ArrayAccess { /* Methods */ abstract public ...

  5. YYModel 源码解读(二)之NSObject+YYModel.h (5)

    好了,之前的博文中详细的解释了一些辅助的类和辅助的函数,接下来就是使用它们来实现酷炫功能的时候,正所谓磨刀不误砍柴工啊 我们先把总的功能罗列出来 1. json转字典              + ( ...

  6. 【转】基于linux下的dm9000网卡移植全分析

    转自:http://blog.sina.com.cn/s/blog_6abf2c04010189ui.html DM9000可以直接与ISA总线相连,也可以与大多数CPU直接相连.Mini2440采用 ...

  7. 对C语言islower、isupper、isdigit函数的测试

    今天朋友问起了这三个函数,我就帮忙测试了下,测试后发现谭浩强第四版课本附录上上讲的不是很严谨. 我们先看下这三个函数介绍: 谭浩强第四版课本附录第396页上这样介绍: 函数名 函数原型 功能 返回值 ...

  8. CentOS7 Jenkins安装

    CentOS7 Jenkins安装 CentOS7 Jenkins安装 Download 从Jenkins下载apache-tomcat-8.0.18.tar.gz Install 安装 上传RPM文 ...

  9. 混合框架中Oracle数据库的还原处理操作

    在较早期的随笔<Oracle如何实现创建数据库.备份数据库及数据导出导入的一条龙操作>粗略介绍了Oracle数据库的备份还原操作,本文想从开发框架的基础上介绍Oracle数据库的脚本或者还 ...

  10. Live555流媒体服务器编译(Windows下)

    最近在回顾之前做过的相关项目,其中包括live555流媒体服务器相关,今天先把live555开源框架在Windows下的编译方法记录一下. live555是一套使用使用开放的标准协议(RTP/RTCP ...