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. C# - 缓存OutputCache(一)基础配置

    本文是通过网上&个人总结的 1. 介绍 OutputCache输出缓存是复制ASP.NET页面,保存在内存的机制.这种行为有助于提高性能,通过返回的缓存达到网页及时响应的目的,减少客户机器需要 ...

  2. iOS 多个播放器同时播放,双击全屏,单击退出全屏

    前言:公司需求如下:点击一个按钮播放一个视频,最多同时播放4个:双击某视频让其全屏,单击再恢复原来的样子.IOS的播放器有两种,MPMoviePlayerController,AVAudioPlaye ...

  3. Memcached和Redis比较

    一.存储 Memcached基本只支持简单的key-value存储方式.Redis除key-value之外,还支持list,set,sorted set,hash等数据结构:Redis支持数据的备份, ...

  4. SQL Server 进制转换函数

    一.背景 前段时间群里的朋友问了一个问题:“在查询时增加一个递增序列,如:0x00000001,即每一个都是36进位(0—9,A--Z),0x0000000Z后面将是0x00000010,生成一个像下 ...

  5. MVVM下listbox默认显示最后一行

    原文地址:http://stackoverflow.com/questions/16866309/listbox-scroll-into-view-with-mvvm public class Scr ...

  6. 谈谈iOS Animation

    零.前言 这里没有太多的代码细节,只是探索iOS动画的基本概念,以及其抽象模型,数学基础等.我们学习一个知识的时候一般有两个部分,抽象部分和形象部分,抽象好比语言的语法,是规则,形象好比具体的句子,可 ...

  7. 【NLP】条件随机场知识扩展延伸(五)

    条件随机场知识扩展延伸 作者:白宁超 2016年8月3日19:47:55 [摘要]:条件随机场用于序列标注,数据分割等自然语言处理中,表现出很好的效果.在中文分词.中文人名识别和歧义消解等任务中都有应 ...

  8. Vertica 高可用性测试

    1.基本概念介绍 2.停止某节点服务 3.测试其他节点访问 1.基本概念介绍 Vertica也是MPP架构的数据库,相比大家熟悉的MPP架构,比如Greenplum和hadoop这些产品,Vertic ...

  9. 浅谈css的伪元素::after和::before

    css中的::after和::before已经被大量地使用在我们日常开发中了,使用他们可以使我们的文档结构更加简洁.但是很多人对::after和::before仍不是特别了解,究竟他们是做什么的?如何 ...

  10. 响应式图片菜单式轮播,兼容手机,平板,PC

    昨天在给自己用bootstrap写一个响应式主业模版时想用一个图片轮播js,看到了bootstrap里面的unslider.js,只有1.7k,很小,很兴奋,但使用到最后发现不兼容手机,当分辨率变化的 ...