python高级之多进程

 

python高级之多进程

本节内容

  1. 多进程概念
  2. Process类
  3. 进程间通讯
  4. 进程同步
  5. 进程池

1.多进程概念

multiprocessing is a package that supports spawning processes using an API similar to the threading module. The multiprocessing package offers both local and remote concurrency,effectively side-stepping the Global Interpreter Lock by using subprocesses instead of threads. Due to this, the multiprocessing module allows the programmer to fully leverage multiple processors on a given machine. It runs on both Unix and Windows.

由于GIL的存在,python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程。Python提供了非常好用的多进程包multiprocessing,只需要定义一个函数,Python会完成其他所有事情。借助这个包,可以轻松完成从单进程到并发执行的转换。multiprocessing支持子进程、通信和共享数据、执行不同形式的同步,提供了Process、Queue、Pipe、Lock等组件。

multiprocessing包是Python中的多进程管理包。与threading.Thread类似,它可以利用multiprocessing.Process对象来创建一个进程。该进程可以运行在Python程序内部编写的函数。该Process对象与Thread对象的用法相同,也有start(), run(), join()的方法。此外multiprocessing包中也有Lock/Event/Semaphore/Condition类 (这些对象可以像多线程那样,通过参数传递给各个进程),用以同步进程,其用法与threading包中的同名类一致。所以,multiprocessing的很大一部份与threading使用同一套API,只不过换到了多进程的情境。

但在使用这些共享API的时候,我们要注意以下几点:

  • 在UNIX平台上,当某个进程终结之后,该进程需要被其父进程调用wait,否则进程成为僵尸进程(Zombie)。所以,有必要对每个Process对象调用join()方法 (实际上等同于wait)。对于多线程来说,由于只有一个进程,所以不存在此必要性。

  • multiprocessing提供了threading包中没有的IPC(比如Pipe和Queue),效率上更高。应优先考虑Pipe和Queue,避免使用Lock/Event/Semaphore/Condition等同步方式 (因为它们占据的不是用户进程的资源)。

  • 多进程应该避免共享资源。在多线程中,我们可以比较容易地共享资源,比如使用全局变量或者传递参数。在多进程情况下,由于每个进程有自己独立的内存空间,以上方法并不合适。此时我们可以通过共享内存和Manager的方法来共享资源。但这样做提高了程序的复杂度,并因为同步的需要而降低了程序的效率。

Process.PID中保存有PID,如果进程还没有start(),则PID为None。

window系统下,需要注意的是要想启动一个子进程,必须加上那句if name == "main",进程相关的要写在这句下面。

函数式调用:

 1 from multiprocessing import Process
2 import time
3 def f(name):
4 time.sleep(1)
5 print('hello', name,time.ctime())
6
7 if __name__ == '__main__':
8 p_list=[]
9 for i in range(3):
10 p = Process(target=f, args=('alvin',))
11 p_list.append(p)
12 p.start()
13 for i in p_list:
14 p.join()
15 print('end')

继承式调用:

 1 from multiprocessing import Process
2 import time
3
4 class MyProcess(Process):
5 def __init__(self):
6 super(MyProcess, self).__init__()
7 #self.name = name
8
9 def run(self):
10 time.sleep(1)
11 print ('hello', self.name,time.ctime())
12
13
14 if __name__ == '__main__':
15 p_list=[]
16 for i in range(3):
17 p = MyProcess()
18 p.start()
19 p_list.append(p)
20
21 for p in p_list:
22 p.join()
23
24 print('end')

获取进程PID及父进程PID

 1 from multiprocessing import Process
2 import os
3 import time
4 def info(title):
5 print(title)
6 print('module name:', __name__)
7 print('parent process:', os.getppid())
8 print('process id:', os.getpid())
9
10
11 def f(name):
12 info('\033[31;1mfunction f\033[0m')
13 print('hello', name)
14
15 if __name__ == '__main__':
16 info('\033[32;1mmain process line\033[0m')
17 time.sleep(100)
18 p = Process(target=info, args=('bob',))
19 p.start()
20 p.join()

2.Process类

构造方法:

Process([group [, target [, name [, args [, kwargs]]]]])

  • group: 线程组,目前还没有实现,库引用中提示必须是None;
  • target: 要执行的方法;
  • name: 进程名;
  • args/kwargs: 要传入方法的参数。

实例方法:

  • is_alive():返回进程是否在运行。
  • join([timeout]):阻塞当前上下文环境的进程程,直到调用此方法的进程终止或到达指定的timeout(可选参数)。
  • start():进程准备就绪,等待CPU调度
  • run():strat()调用run方法,如果实例进程时未制定传入target,这star执行t默认run()方法。
  • terminate():不管任务是否完成,立即停止工作进程

属性:

  • authkey
  • daemon:和线程的setDeamon功能一样
  • exitcode(进程在运行时为None、如果为–N,表示被信号N结束)
  • name:进程名字。
  • pid:进程号。

例子:

 1 import time
2 from multiprocessing import Process
3
4 def foo(i):
5 time.sleep(1)
6 print (p.is_alive(),i,p.pid)
7 time.sleep(1)
8
9 if __name__ == '__main__':
10 p_list=[]
11 for i in range(10):
12 p = Process(target=foo, args=(i,))
13 #p.daemon=True
14 p_list.append(p)
15
16 for p in p_list:
17 p.start()
18 # for p in p_list:
19 # p.join()
20
21 print('main process end')

3.进程间通讯

不同进程间内存是不共享的,要想实现两个进程间的数据交换,可以用以下方法:

Queues

使用方法跟threading里的queue类似:

 1 from multiprocessing import Process, Queue
2
3 def f(q,n):
4 q.put([42, n, 'hello'])
5
6 if __name__ == '__main__':
7 q = Queue()
8 p_list=[]
9 for i in range(3):
10 p = Process(target=f, args=(q,i))
11 p_list.append(p)
12 p.start()
13 print(q.get())
14 print(q.get())
15 print(q.get())
16 for i in p_list:
17 i.join()

Pipes

The Pipe() function returns a pair of connection objects connected by a pipe which by default is duplex (two-way).

pipe函数返回一对连接对象,使用管道,默认是双工模式

For example:

 1 from multiprocessing import Process, Pipe
2
3 def f(conn):
4 conn.send([42, None, 'hello'])
5 conn.close()
6
7 if __name__ == '__main__':
8 parent_conn, child_conn = Pipe()
9 p = Process(target=f, args=(child_conn,))
10 p.start()
11 print(parent_conn.recv()) # prints "[42, None, 'hello']"
12 p.join()

The two connection objects returned by Pipe() represent the two ends of the pipe. Each connection object has send() and recv() methods (among others). Note that data in a pipe may become corrupted if two processes (or threads) try to read from or write to the same end of the pipe at the same time. Of course there is no risk of corruption from processes using different ends of the pipe at the same time.

pipe会返回两个连接对象代表终端连接的两个进程。每个连接对象都有send和recv方法。如果两个进程在同一时刻读取数据或者写入数据,将会破坏这个管道。当然,在进程中同时使用同一个pipe的不同终端是不会有这个风险的。。。(无法理解)

Managers A manager object returned by Manager() controls a server process which holds Python objects and allows other processes to manipulate them using proxies.

A manager returned by Manager() will support types list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Barrier, Queue, Value and Array. For example,

 1 from multiprocessing import Process, Manager
2
3 def f(d, l,n):
4 d[n] = '1'
5 d['2'] = 2
6 d[0.25] = None
7 l.append(n)
8 print(l)
9
10 if __name__ == '__main__':
11 with Manager() as manager:
12 d = manager.dict()
13
14 l = manager.list(range(5))
15 p_list = []
16 for i in range(10):
17 p = Process(target=f, args=(d, l,i))
18 p.start()
19 p_list.append(p)
20 for res in p_list:
21 res.join()
22
23 print(d)
24 print(l)

4.进程同步

进程同步也可以使用lock实现,不过这个lock是在multiprocessing模块中的。

例子:

 1 from multiprocessing import Process, Lock
2
3 def f(l, i):
4 l.acquire()
5 try:
6 print('hello world', i)
7 finally:
8 l.release()
9
10 if __name__ == '__main__':
11 lock = Lock()
12
13 for num in range(10):
14 Process(target=f, args=(lock, num)).start()

5.进程池

进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。

进程池中有两个方法:

  • apply # 一个一个执行子进程
  • apply_async # 并发执行子进程

示例:

 1 from  multiprocessing import Process,Pool
2 import time
3
4 def Foo(i):
5 time.sleep(2)
6 return i+100
7
8 def Bar(arg):
9 print('-->exec done:',arg)
10
11 pool = Pool(5)
12
13 for i in range(10):
14 pool.apply_async(func=Foo, args=(i,),callback=Bar)
15 #pool.apply(func=Foo, args=(i,))
16
17 print('end')
18 pool.close()
19 pool.join()
 
分类: python高级

第八篇:python高级之多进程的更多相关文章

  1. python高级之多进程

    python高级之多进程 本节内容 多进程概念 Process类 进程间通讯 进程同步 进程池 1.多进程概念 multiprocessing is a package that supports s ...

  2. 第七篇: python高级之多线程

    21 interest=0.05 22 count=amount+amount*interest 23 24 self.withdraw(count) 25 26 27 def transfer(_f ...

  3. Python高级编程-多进程

    要让Python程序实现多进程(multiprocessing),我们先了解操作系统的相关知识. Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊.普通的函数调用,调用一次,返回 ...

  4. 【Python之路】第八篇--Python基础之网络编程

    Socket socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. sock ...

  5. Python之路(第八篇)Python内置函数、zip()、max()、min()

    一.python内置函数 abs() 求绝对值 例子 print(abs(-2)) all() 把序列中每一个元素做布尔运算,如果全部都是true,就返回true, 但是如果是空字符串.空列表也返回t ...

  6. 第十八篇 js高级知识---作用域链

    一直有想法去写写js方面的东西,我个人是最喜欢js这门语言,喜欢的他的自由和强大,虽然作为脚本语言有很多限制的地方,但也不失为一个好的语言,尤其是在H5出现之后.下面开始说说js的方面的东西,由于自己 ...

  7. 第八篇 Python异常

    程序在运行时,如果Python解释器遇到一个错误,会停止程序的执行,并且提示一些错误信息,这就是异常,程序通知执行并且提示错误信息,这个动作,我们通常称之为:抛出异常. 1.简单的捕获异常的语法 在程 ...

  8. 第八篇Python基本数据类型之列表、元组与字典

    列表 写在最前,必须要会的:append(),extend(),insert(),索引,切片,循环 list  是一个类,是个对象 列表用 方括号[]括起来的,[]内以逗号分割每个元素,列表中的元素可 ...

  9. 第十八篇 .NET高级技术之Linq与EF Code-First Fluent API基础讲解

    1.FluentApi简介 在这里提供了一个fluentapi基础的DEMO然后咱们在进一步的学习,直接上干货. 第一步在数据库创建一个表:person 第二步:新建控制台程序FluentAPI 第三 ...

随机推荐

  1. js将数字转换成大写的人民币表达式

    function changeNumMoneyToChinese(money) { var cnNums = new Array("零", "壹", " ...

  2. 解决类型“System.Web.UI.UpdatePanel”不具有名为“Gridview”的公共属性,

    类型“system.web.ui.updatepanel” 不具有名为“XXX”的公共属性,其实原因很简单.就是少了一个<ContentTemplate></ContentTempl ...

  3. bzoj 3669: [Noi2014]魔法森林 动态树

    3669: [Noi2014]魔法森林 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 363  Solved: 202[Submit][Status] ...

  4. CTSC模拟题 树上的路径

    Description 给定一棵\(N\)个结点的树,结点用正整数\(1 \dots N\)编号,每条边有一个正整数权值.用\(d(a, b)\)表示从结点\(a\)到结点\(b\)路径上经过边的权值 ...

  5. BZOJ 1026 windy数

    Description windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道,在A和B之间,包括A和B,总共有多少个windy数? In ...

  6. 【转】python3 发邮件实例(包括:文本、html、图片、附件、SSL、群邮件)

    特别留意群邮件方式,这是工作中用得多的. 附件,HTML,图片,都需要的. 文件形式的邮件 [python] view plain copy 1.#!/usr/bin/env python3 2.#c ...

  7. Java实现字符串反转

    替换原则:index k 的值和 n-k 的值进行交换.(始终记住程序员的n.k都是字符串的实际位置.) 乘除的最基本实现还是来源于移位操作. public String reverse(String ...

  8. Linux Shell编程(21)——复杂命令

    更高级的用户命令find-exec COMMAND \;在每一个find 匹配到的文件执行 COMMAND 命令. 命令序列以 ; 结束( ";" 是 转义符 以保证 shell ...

  9. 几款常用Eclipse java插件

    以下是我最近常用的几款Eclipse java插件: ADT Plugin https://dl-ssl.google.com/android/eclipse/ WindowBuilder Pro  ...

  10. UIView hitTest的原理

    [转自:http://blog.sina.com.cn/s/blog_59fb90df0101ab26.html] UIView 两个方法: - (UIView *)hitTest:(CGPoint) ...