【转】【Python】Python多进程与多线程
1.1 multiprocessing
multiprocessing是多进程模块,多进程提供了任务并发性,能充分利用多核处理器。避免了GIL(全局解释锁)对资源的影响。
有以下常用类:
类 |
描述 |
Process(group=None, target=None, name=None, args=(), kwargs={}) | 派生一个进程对象,然后调用start()方法启动 |
Pool(processes=None, initializer=None, initargs=()) |
返回一个进程池对象,processes进程池进程数量 |
Pipe(duplex=True) | 返回两个连接对象由管道连接 |
Queue(maxsize=0) | 返回队列对象,操作方法跟Queue.Queue一样 |
multiprocessing.dummy | 这个库是用于实现多线程 |
Process()类有以下些方法:
run() | |
start() | 启动进程对象 |
join([timeout]) | 等待子进程终止,才返回结果。可选超时。 |
name | 进程名字 |
is_alive() | 返回进程是否存活 |
daemon | 进程的守护标记,一个布尔值 |
pid | 返回进程ID |
exitcode | 子进程退出状态码 |
terminate() | 终止进程。在unix上使用SIGTERM信号,在windows上使用TerminateProcess()。 |
Pool()类有以下些方法:
apply(func, args=(), kwds={}) | 等效内建函数apply() |
apply_async(func, args=(), kwds={}, callback=None) | 异步,等效内建函数apply() |
map(func, iterable, chunksize=None) | 等效内建函数map() |
map_async(func, iterable, chunksize=None, callback=None) | 异步,等效内建函数map() |
imap(func, iterable, chunksize=1) | 等效内建函数itertools.imap() |
imap_unordered(func, iterable, chunksize=1) | 像imap()方法,但结果顺序是任意的 |
close() | 关闭进程池 |
terminate() | 终止工作进程,垃圾收集连接池对象 |
join() | 等待工作进程退出。必须先调用close()或terminate() |
Pool.apply_async()和Pool.map_aysnc()又提供了以下几个方法:
get([timeout]) | 获取结果对象里的结果。如果超时没有,则抛出TimeoutError异常 |
wait([timeout]) | 等待可用的结果或超时 |
ready() | 返回调用是否已经完成 |
successful() |
举例:
1)简单的例子,用子进程处理函数
from multiprocessing import Process
import os
def worker(name):
print name
print 'parent process id:', os.getppid()
print 'process id:', os.getpid()
if __name__ == '__main__':
p = Process(target=worker, args=('function worker.',))
p.start()
p.join()
print p.name # python test.py
function worker.
parent process id: 9079
process id: 9080
Process-1
Process实例传入worker函数作为派生进程执行的任务,用start()方法启动这个实例。
2)加以说明join()方法
from multiprocessing import Process
import os
def worker(n):
print 'hello world', n
if __name__ == '__main__':
print 'parent process id:', os.getppid()
for n in range(5):
p = Process(target=worker, args=(n,))
p.start()
p.join()
print 'child process id:', p.pid
print 'child process name:', p.name # python test.py
parent process id: 9041
hello world 0
child process id: 9132
child process name: Process-1
hello world 1
child process id: 9133
child process name: Process-2
hello world 2
child process id: 9134
child process name: Process-3
hello world 3
child process id: 9135
child process name: Process-4
hello world 4
child process id: 9136
child process name: Process-5 # 把p.join()注释掉再执行
# python test.py
parent process id: 9041
child process id: 9125
child process name: Process-1
child process id: 9126
child process name: Process-2
child process id: 9127
child process name: Process-3
child process id: 9128
child process name: Process-4
hello world 0
hello world 1
hello world 3
hello world 2
child process id: 9129
child process name: Process-5
hello world 4
可以看出,在使用join()方法时,输出的结果都是顺序排列的。相反是乱序的。因此join()方法是堵塞父进程,要等待当前子进程执行完后才会继续执行下一个子进程。否则会一直生成子进程去执行任务。
在要求输出的情况下使用join()可保证每个结果是完整的。
3)给子进程命名,方便管理
from multiprocessing import Process
import os, time
def worker1(n):
print 'hello world', n
def worker2():
print 'worker2...'
if __name__ == '__main__':
print 'parent process id:', os.getppid()
for n in range(3):
p1 = Process(name='worker1', target=worker1, args=(n,))
p1.start()
p1.join()
print 'child process id:', p1.pid
print 'child process name:', p1.name
p2 = Process(name='worker2', target=worker2)
p2.start()
p2.join()
print 'child process id:', p2.pid
print 'child process name:', p2.name # python test.py
parent process id: 9041
hello world 0
child process id: 9248
child process name: worker1
hello world 1
child process id: 9249
child process name: worker1
hello world 2
child process id: 9250
child process name: worker1
worker2...
child process id: 9251
child process name: worker2
4)设置守护进程,父进程退出也不影响子进程运行
from multiprocessing import Process
def worker1(n):
print 'hello world', n
def worker2():
print 'worker2...'
if __name__ == '__main__':
for n in range(3):
p1 = Process(name='worker1', target=worker1, args=(n,))
p1.daemon = True
p1.start()
p1.join()
p2 = Process(target=worker2)
p2.daemon = False
p2.start()
p2.join()
5)使用进程池
#!/usr/bin/python
# -*- coding: utf-8 -*-
from multiprocessing import Pool, current_process
import os, time, sys
def worker(n):
print 'hello world', n
print 'process name:', current_process().name # 获取当前进程名字
time.sleep(1) # 休眠用于执行时有时间查看当前执行的进程
if __name__ == '__main__':
p = Pool(processes=3)
for i in range(8):
r = p.apply_async(worker, args=(i,))
r.get(timeout=5) # 获取结果中的数据
p.close() # python test.py
hello world 0
process name: PoolWorker-1
hello world 1
process name: PoolWorker-2
hello world 2
process name: PoolWorker-3
hello world 3
process name: PoolWorker-1
hello world 4
process name: PoolWorker-2
hello world 5
process name: PoolWorker-3
hello world 6
process name: PoolWorker-1
hello world 7
process name: PoolWorker-2
进程池生成了3个子进程,通过循环执行8次worker函数,进程池会从子进程1开始去处理任务,当到达最大进程时,会继续从子进程1开始。
在运行此程序同时,再打开一个终端窗口会看到生成的子进程:
# ps -ef |grep python
root 40244 9041 4 16:43 pts/3 00:00:00 python test.py
root 40245 40244 0 16:43 pts/3 00:00:00 python test.py
root 40246 40244 0 16:43 pts/3 00:00:00 python test.py
root 40247 40244 0 16:43 pts/3 00:00:00 python test.py
6)进程池map()方法
map()方法是将序列中的元素通过函数处理返回新列表。
from multiprocessing import Pool
def worker(url):
return 'http://%s' % url
urls = ['www.baidu.com', 'www.jd.com']
p = Pool(processes=2)
r = p.map(worker, urls)
p.close()
print r # python test.py
['http://www.baidu.com', 'http://www.jd.com']
7)Queue进程间通信
multiprocessing支持两种类型进程间通信:Queue和Pipe。
Queue库已经封装到multiprocessing库中,在第十章 Python常用标准库已经讲解到Queue库使用,有需要请查看以前博文。
例如:一个子进程向队列写数据,一个子进程读取队列数据
#!/usr/bin/python
# -*- coding: utf-8 -*-
from multiprocessing import Process, Queue
# 写数据到队列
def write(q):
for n in range(5):
q.put(n)
print 'Put %s to queue.' % n
# 从队列读数据
def read(q):
while True:
if not q.empty():
value = q.get()
print 'Get %s from queue.' % value
else:
break
if __name__ == '__main__':
q = Queue()
pw = Process(target=write, args=(q,))
pr = Process(target=read, args=(q,))
pw.start()
pw.join()
pr.start()
pr.join() # python test.py
Put 0 to queue.
Put 1 to queue.
Put 2 to queue.
Put 3 to queue.
Put 4 to queue.
Get 0 from queue.
Get 1 from queue.
Get 2 from queue.
Get 3 from queue.
Get 4 from queue.
8)Pipe进程间通信
from multiprocessing import Process, Pipe
def f(conn):
conn.send([42, None, 'hello'])
conn.close()
if __name__ == '__main__':
parent_conn, child_conn = Pipe()
p = Process(target=f, args=(child_conn,))
p.start()
print parent_conn.recv()
p.join() # python test.py
[42, None, 'hello']
Pipe()创建两个连接对象,每个链接对象都有send()和recv()方法,
9)进程间对象共享
Manager类返回一个管理对象,它控制服务端进程。提供一些共享方式:Value()、Array()、list()、dict()、Event()等
创建Manger对象存放资源,其他进程通过访问Manager获取。
from multiprocessing import Process, Manager
def f(v, a, l, d):
v.value = 100
a[0] = 123
l.append('Hello')
d['a'] = 1
mgr = Manager()
v = mgr.Value('v', 0)
a = mgr.Array('d', range(5))
l = mgr.list()
d = mgr.dict()
p = Process(target=f, args=(v, a, l, d))
p.start()
p.join()
print(v)
print(a)
print(l)
print(d) # python test.py
Value('v', 100)
array('d', [123.0, 1.0, 2.0, 3.0, 4.0])
['Hello']
{'a': 1}
10)写一个多进程的例子
比如:多进程监控URL是否正常
from multiprocessing import Pool, current_process
import urllib2
urls = [
'http://www.baidu.com',
'http://www.jd.com',
'http://www.sina.com',
'http://www.163.com',
]
def status_code(url):
print 'process name:', current_process().name
try:
req = urllib2.urlopen(url, timeout=5)
return req.getcode()
except urllib2.URLError:
return
p = Pool(processes=4)
for url in urls:
r = p.apply_async(status_code, args=(url,))
if r.get(timeout=5) == 200:
print "%s OK" %url
else:
print "%s NO" %url # python test.py
process name: PoolWorker-1
http://www.baidu.com OK
process name: PoolWorker-2
http://www.jd.com OK
process name: PoolWorker-3
http://www.sina.com OK
process name: PoolWorker-4
http://www.163.com OK
1.2 threading
threading模块类似于multiprocessing多进程模块,使用方法也基本一样。threading库是对thread库进行二次封装,我们主要用到Thread类,用Thread类派生线程对象。
1)使用Thread类实现多线程
from threading import Thread, current_thread
def worker(n):
print 'thread name:', current_thread().name
print 'hello world', n for n in range(5):
t = Thread(target=worker, args=(n, ))
t.start()
t.join() # 等待主进程结束 # python test.py
thread name: Thread-1
hello world 0
thread name: Thread-2
hello world 1
thread name: Thread-3
hello world 2
thread name: Thread-4
hello world 3
thread name: Thread-5
hello world 4
2)还有一种方式继承Thread类实现多线程,子类可以重写__init__和run()方法实现功能逻辑。
#!/usr/bin/python
# -*- coding: utf-8 -*-
from threading import Thread, current_thread
class Test(Thread):
# 重写父类构造函数,那么父类构造函数将不会执行
def __init__(self, n):
Thread.__init__(self)
self.n = n
def run(self):
print 'thread name:', current_thread().name
print 'hello world', self.n
if __name__ == '__main__':
for n in range(5):
t = Test(n)
t.start()
t.join() # python test.py
thread name: Thread-1
hello world 0
thread name: Thread-2
hello world 1
thread name: Thread-3
hello world 2
thread name: Thread-4
hello world 3
thread name: Thread-5
hello world 4
3)Lock
from threading import Thread, Lock, current_thread
lock = Lock()
class Test(Thread):
# 重写父类构造函数,那么父类构造函数将不会执行
def __init__(self, n):
Thread.__init__(self)
self.n = n
def run(self):
lock.acquire() # 获取锁
print 'thread name:', current_thread().name
print 'hello world', self.n
lock.release() # 释放锁
if __name__ == '__main__':
for n in range(5):
t = Test(n)
t.start()
t.join()
众所周知,Python多线程有GIL全局锁,意思是把每个线程执行代码时都上了锁,执行完成后会自动释放GIL锁,意味着同一时间只有一个线程在运行代码。由于所有线程共享父进程内存、变量、资源,很容易多个线程对其操作,导致内容混乱。
当你在写多线程程序的时候如果输出结果是混乱的,这时你应该考虑到在不使用锁的情况下,多个线程运行时可能会修改原有的变量,导致输出不一样。
由此看来Python多线程是不能利用多核CPU提高处理性能,但在IO密集情况下,还是能提高一定的并发性能。也不必担心,多核CPU情况可以使用多进程实现多核任务。Python多进程是复制父进程资源,互不影响,有各自独立的GIL锁,保证数据不会混乱。能用多进程就用吧!
原文地址:http://lizhenliang.blog.51cto.com/7876557/1875753
【转】【Python】Python多进程与多线程的更多相关文章
- Python 中多进程、多线程、协程
进程: 一个运行的程序(代码)就是一个进程,没有运行的代码叫程序,进程是系统资源分配的最小单位,进程拥有自己独立的内存空间,所以进程间数据不共享.开销大. 线程: 调度执行的最小单位,也叫执行路径,不 ...
- Python的多进程和多线程
进程和线程 进程是系统进行资源分配的最小单位,线程是系统进行调度执行的最小单位: 一个应用程序至少包含一个进程,一个进程至少包含一个线程: 每个进程在执行过程中拥有独立的内存空间,而一个进程中的线程之 ...
- python之多进程and多线程
图文来自互联网 一.什么是进程和线程 (https://jq.qq.com/?_wv=1027&k=rX9CWKg4) 进程是分配资源的最小单位,线程是系统调度的最小单位. 当应用程序运行时最 ...
- Python之多进程和多线程
目标: 1.os.fork简单示例 2.使用os.fork多进程测试IP是否在线 3.使用os.fork多进程解决tcpserver多客户端连接问题 4.多线程测试IP地址是否在线 1.os.fork ...
- 【python】多进程、多线程、序列
一.多进程 1.子进程永远返回0,而父进程返回子进程的ID.这样做的理由是,一个父进程可以fork出很多子进程,所以,父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程 ...
- 【转】Python中的GIL、多进程和多线程
转自:http://lesliezhu.github.io/public/2015-04-20-python-multi-process-thread.html 目录 1. GIL(Global In ...
- Python中的多进程与多线程(二)
在上一章中,学习了Python多进程编程的一些基本方法:使用跨平台多进程模块multiprocessing提供的Process.Pool.Queue.Lock.Pipe等类,实现子进程创建.进程池(批 ...
- python采用 多进程/多线程/协程 写爬虫以及性能对比,牛逼的分分钟就将一个网站爬下来!
首先我们来了解下python中的进程,线程以及协程! 从计算机硬件角度: 计算机的核心是CPU,承担了所有的计算任务.一个CPU,在一个时间切片里只能运行一个程序. 从操作系统的角度: 进程和线程,都 ...
- 在python中单线程,多线程,多进程对CPU的利用率实测以及GIL原理分析
首先关于在python中单线程,多线程,多进程对cpu的利用率实测如下: 单线程,多线程,多进程测试代码使用死循环. 1)单线程: 2)多线程: 3)多进程: 查看cpu使用效率: 开始观察分别执行时 ...
- 学习笔记--python中使用多进程、多线程加速文本预处理
一.任务描述 最近尝试自行构建skip-gram模型训练word2vec词向量表.其中有一步需要统计各词汇的出现频率,截取出现频率最高的10000个词汇进行保留,形成常用词词典.对于这个问题,我建立了 ...
随机推荐
- C#整数三种强制类型转换int、Convert.ToInt32()、int.Parse()、string到object 的区别
1.int适合简单数据类型之间的转换,C#的默认整型是int32(不支持bool型); 2.int.Parse(string sParameter)是个构造函数,参数类型只支持string类型; 3. ...
- UI设计文本框解决Placeholder的在IE10 以下 IE 9 IE8 IE 7 的兼容问题
创建JS文件 placeholderfriend.js (function($) { /** * 牛叉的解决方案 */ var placeholderfriend = { focus: functio ...
- 在javascript中获取一个对象内属性的个数
var foo = {a1:'1',a2:'2',a3:'3'}; //获得对象所有属性的数组 Object.getOwnPropertyNames(foo); > [ 'a1', 'a2', ...
- 每日英语:China's Bigger Innovation Problem
Last month's Third Plenum meeting of Chinese leaders seemed to signal Beijing's intention to experim ...
- 关于fork()函数的精辟分析
http://blog.csdn.net/yanh_lzu/article/details/2311644 第一贴:cu上关于fork()函数的精辟分析 声明:在别人的博客上看到这篇文章,真的很精 ...
- 9个绚丽多彩的HTML5进度条动画赏析
进度条在网页应用中越来越广泛了,特别是现在的页面异步局部刷新时代,进度条可以让用户更好的等待操作结果.本文要分享9款绚丽多彩的HTML5进度条动画,有很多还是挺实用的,效果也非常不错. 1.CSS3发 ...
- 【机器学习】粗糙集属性约简算法与mRMR算法的本质区别
1. 粗糙集属性约简算法仅仅选出属性重要度大的条件加入约减中,没有考虑约简中条件属性相互之间的冗余性,得到的约简往往不是都必要的,即含有冗余属性. 2. mRMR算法则除了考虑特征与类别之间的相关性, ...
- Redhat6.5安装DB2 Express-C版本
Linux Redhat6.5安装DB2 Express-C版本: 创建相关用户和组 创建用户组: groupdel db2iadm1 groupadd -g 999 db2iadm1 groupad ...
- RelativeLayout 相对父级元素布局
相对布局,用来设置相对父级视图的位置 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android ...
- java框架篇---Struts2的处理流程
一.Struts2的处理流程: 客户端产生一个HttpServletRequest的请求,该请求被提交到一系列的标准过滤器(Filter)组建链中(如ActionContextCleanUp:它主要是 ...