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. 记一次jdk升级引起的 Unsupported major.minor version 51.0

    之前jdk 一直是1.6,tomcat 是6.x 版本,, 现在引入的新的jar, 出现 Caused by: java.lang.UnsupportedClassVersionError: org/ ...

  2. .Net使用system.Security.Cryptography.RNGCryptoServiceProvider类与System.Random类生成随机数

    .Net中我们通常使用Random类生成随机数,在一些场景下,我却发现Random生成的随机数并不可靠,在下面的例子中我们通过循环随机生成10个随机数: ; i < ; i++) { Rando ...

  3. Electron安装

    1.安装nodejs和npm 官网下载地址:https://nodejs.org/en/download/ 安装包:下载.msi 安装完成后: nodejs.npm都会安装好,path环境变量也自动设 ...

  4. Hadoop的学习--安装配置与使用

    安装配置 系统:Ubuntu14.04 java:1.7.0_75 相关资料 官网 下载地址 官网文档 安装 我们需要关闭掉防火墙,命令如下: sudo ufw disable 下载2.6.5的版本, ...

  5. 简单动态规划-LeetCode198

    题目:House Robber You are a professional robber planning to rob houses along a street. Each house has ...

  6. 中文分词工具探析(二):Jieba

    1. 前言 Jieba是由fxsjy大神开源的一款中文分词工具,一款属于工业界的分词工具--模型易用简单.代码清晰可读,推荐有志学习NLP或Python的读一下源码.与采用分词模型Bigram + H ...

  7. [入门级] 基于 visual studio 2010 mvc4 的图书管理系统开发初步 (二)

    [入门级] 基于 visual studio 2010 mvc4 的图书管理系统开发初步 (二) Date  周六 10 一月 2015 By 钟谢伟 Category website develop ...

  8. C#得到某月最后一天晚上23:59:59和某月第一天00:00:00

    项目需求: 某学校订单截止操作时间的上一个月最后一天晚上23:59:59 为止所有支付的订单统计: 代码: /// <summary> /// 通过学校和截止时间得到订单 /// < ...

  9. 在DevExpress程序中使用内置的图标构建美观的界面元素

    在我们一般的程序中,为一般的界面元素添加一定的图标展示,有助于提升界面的整体的美观.结合排版布局,以及固定场景的图标,往往给用户非常好的直观感受:统一.美观.易理解.因此在一般的程序界面中,都尽量在略 ...

  10. mongodb在java中的查询

    mongodb 根据_id 查询记录: public Price queryPriceById(String id) throws Exception { return mongoTemplate.f ...