python 实现多进程


参考链接: https://morvanzhou.github.io/tutorials/python-basic/multiprocessing/

python中实现多进程的模块:multiprocessing

注意:在windows系统下,要想启动一个子进程,必须把进程相关的内容写在”if __name__ == “__main__” ”,这句话下面。

具体实现模块

1、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:进程号。

  • 例子:

 import multiprocessing

 def job(a,d):
  print('aaaaa') if __name__ == “__main__”:
  p1 = multiprocessing.Process(target=job,args=(1,2))
  p1.start()
  p1.join()

2、Pool模块

  • 实现功能:

创建管理进程池。提供指定数量的进程供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来执行它。在共享资源时,只能使用Multiprocessing.Manager类,而不能使用Queue或者Array。

  • 构造方法:

Pool([processes[, initializer[, initargs[, maxtasksperchild[, context]]]]])

processes :使用的工作进程的数量,如果processes是None那么使用 os.cpu_count()返回的数量。(Pool默认大小是CPU的核数,我们也可以通过在Pool中传入processes参数即可自定义需要的核数量)
initializer: 如果initializer是None,那么每一个工作进程在开始的时候会调用initializer(*initargs)。
maxtasksperchild:工作进程退出之前可以完成的任务数,完成后用一个新的工作进程来替代原进程,来让闲置的资源被释放。maxtasksperchild默认是None,意味着只要Pool存在工作进程就会一直存活。
context: 用在制定工作进程启动时的上下文,一般使用 multiprocessing.Pool() 或者一个context对象的Pool()方法来创建一个池,两种方法都适当的设置了context。

  • 实例方法:

apply_async(func[, args[, kwds[, callback]]]) 它是非阻塞。
apply(func[, args[, kwds]])是阻塞的。
close() 关闭pool,使其不在接受新的任务。
terminate() 关闭pool,结束工作进程,不在处理未完成的任务。
join() 主进程阻塞,等待子进程的退出, join方法要在close或terminate之后使用。

  • Pool使用方法:

1、Pool+map函数

  • 用map()获取结果,在map()中需要放入函数和需要迭代运算的值,然后它会自动分配给CPU核,返回结果。
  • 说明:此写法缺点在于只能通过map向函数传递一个参数。
 from multiprocessing import Pool

 def test(i):
print i if __name__=="__main__":
lists=[1,2,3]
pool=Pool(processes=2) #定义最大的进程数
pool.map(test,lists) #lists必须是一个可迭代变量。
pool.close()
pool.join()

2、异步进程池(非阻塞)

  • apply_async()只能放入一组参数,并返回一个结果,如果想得到map()的效果需要通过迭代。
 from multiprocessing import Pool

 def test(i):
print i if __name__=="__main__":
pool = Pool(processes=10)
for i in xrange(500):
'''
For循环中执行步骤:
(1)循环遍历,将500个子进程添加到进程池(相对父进程会阻塞)
(2)每次执行10个子进程,等一个子进程执行完后,立马启动新的子进程。(相对父进程不阻塞)
apply_async为异步进程池写法。
异步指的是启动子进程的过程,与父进程本身的执行(print)是异步的,而For循环中往进程池添加子进程的过程,与父进程本身的执行却是同步的。
'''
pool.apply_async(test, args=(i,)) #维持执行的进程总数为10,当一个进程执行完后启动一个新进程.
print“test”
pool.close()
pool.join()

代码说明:

执行顺序:For循环内执行了2个步骤,第一步:将500个对象放入进程池(阻塞)。第二步:同时执行10个子进程(非阻塞),有结束的就立即添加,维持10个子进程运行。(apply_async方法的会在执行完for循环的添加步骤后,直接执行后面的print语句,而apply方法会等所有进程池中的子进程运行完以后再执行后面的print语句)

注意:调用join之前,先调用close或者terminate方法,否则会出错。执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束。

3、同步进程池(阻塞)

 from multiprocessing import Pool

 def test(p):
print p
time.sleep(3) if __name__=="__main__":
pool = Pool(processes=10)
for i in xrange(500):
'''
实际测试发现,for循环内部执行步骤:
(1)遍历500个可迭代对象,往进程池放一个子进程
(2)执行这个子进程,等子进程执行完毕,再往进程池放一个子进程,再执行。(同时只执行一个子进程)
for循环执行完毕,再执行print函数。
'''
pool.apply(test, args=(i,)) #维持执行的进程总数为10,当一个进程执行完后启动一个新进程.
print“test”
pool.close()
pool.join()

代码说明:

for循环内执行的步骤顺序,往进程池中添加一个子进程,执行子进程,等待执行完毕再添加一个子进程…..等500个子进程都执行完了,再执行print “test”。(从结果来看,并没有多进程并发

3、Queue模块

  • 实现功能:

将每个核或线程的运算结果放在队列中,等到每个线程或核运行完毕后再从队列中取出结果, 继续加载运算。原因很简单, 多线程调用的函数不能有返回值, 所以使用Queue存储多个线程运算的结果

  • 例子:

 import multiprocessing as mp

 def job(q):
res=0
for i in range(1000):
res+=i+i**2+i**3
q.put(res) #queue if __name__=='__main__':
q = mp.Queue()
p1 = mp.Process(target=job,args=(q,))
p2 = mp.Process(target=job,args=(q,))
p1.start()
p2.start()
p1.join()
p2.join()
res1 = q.get()
res2 = q.get()
print(res1+res2)

4、Pipe模块

  • 实现功能:

用来管道操作。

5、Manager模块

  • 实现功能:

Manager模块常与Pool模块一起使用,作用是共享资源。

6、Lock模块(进程锁)

  • 实现功能:

当多个进程需要访问共享资源的时候,Lock可以用来避免访问的冲突。

  • 实现步骤:

1)首先需要定义一个进程锁

l = multiprocessing.Lock()    # 定义一个进程锁

2)然后将进程锁的信息传入各个进程中

p1 = multiprocessing.Process(target=job, args=(v,1,l))    # 需要将Lock传入
p2 = multiprocessing.Process(target=job, args=(v,3,l))

3)在job()中设置进程锁的使用,保证运行时一个进程的对锁内内容的独占

  • 例子:

 import multiprocessing as mp

 def job(v, num, l):
l.acquire() # 锁住
for _ in range(5):
time.sleep(0.1)
v.value += num # 获取共享内存
print(v.value)
l.release() # 释放 def multicore():
l = mp.Lock() # 定义一个进程锁
v = mp.Value('i', 0) # 定义共享内存
p1 = mp.Process(target=job, args=(v,1,l)) # 需要将lock传入
p2 = mp.Process(target=job, args=(v,3,l))
p1.start()
p2.start()
p1.join()
p2.join() if __name__ == '__main__':
multicore()

共享内存

Multiprocessing类中共享资源可以使用3种方式,分别是Queue,Array,Manager。

1、Queue类

使用Multiprocessing.Queue类,共享资源(share memory)(只适用Process类,不能再Pool进程池中使用)

 from multiprocessing import Process, Queue

 def test(queue):
queue.put("Hello World") if __name__ == '__main__':
q = Queue()
p = Process(target=test, args=(q,)) #需要将q对象传递给子进程
p.start()
Print q.get()

2、Array、Value类

使用Multiprocessing.Array类,共享资源(share memory)(只适用于Process类,无法与Pool一起使用)

 from multiprocessing import Process, Array

 def test(a):
for i in range(len(a)):
a[i] = -a[i] if__name__ == '__main__':
arr = Array('i', range(10))
p = Process(target=test, args=(arr)) #需要将arr对象传递给子进程
p.start()
p.join()
print arr[:]
  • 单值:Value

  我们可以通过使用Value数据存储在一个共享的内存表中。

 import multiprocessing as mp 
value1 = mp.Value('i', 0)
value2 = mp.Value('d', 3.14)
  
# 其中d和i参数用来设置数据类型的,d表示一个双精浮点类型,i表示一个带符号的整型。
  • 列表:Array

  在Python的mutiprocessing中,有还有一个Array类,可以和共享内存交互,来实现在进程之间共享数据。

 array = mp.Array('i', [1, 2, 3, 4])
  
#这里的Array和numpy中的不同,它只能是一维的,不能是多维的。同样和Value 一样,需要定义数据形式,否则会报错。

3、Manager类

使用Multiprocessing.Manager类,共享资源。(可以适用Pool类)
实例目的:父进程在执行子进程的过程中,同步判断一个公共资源值,如果满足条件则结束所有进程。

 from multiprocessing import Manager

 def test(i,lists):
print i
lists.append(i) if __name__=="__main__":
pool=Pool()
lists=Manager().list() #Manager类实例化代码只能写在main()函数里面
for i in xrange(10000000):
if len(lists)<=0:
'''
在创建子进程时,需要将lists对象传入,不然无法共享。
'''
pool.apply_async(test,args=(i,lists))##需要将lists对象传递给子进程,这里比较耗资源,原因可能是因为Manager类是基于通信的。
else:
break

  

  • 父进程中的全局变量能被子进程共享吗?

解答:不行,因为每个进程享有独立的内存数据,如果想要共享资源,可以使用Manage类,或者Queue等模块。

进程与线程(2)- python实现多进程的更多相关文章

  1. Python进阶(4)_进程与线程 (python并发编程之多进程)

    一.python并发编程之多进程 1.1 multiprocessing模块介绍 由于GIL的存在,python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大 ...

  2. 进程 vs. 线程(python的协程)(转廖雪峰老师python教程)

    我们介绍了多进程和多线程,这是实现多任务最常用的两种方式.现在,我们来讨论一下这两种方式的优缺点. 首先,要实现多任务,通常我们会设计Master-Worker模式,Master负责分配任务,Work ...

  3. Python基础进程和线程

    一 背景知识 进程的概念起源于操作系统,是操作系统最核心的概念. 进程是对正在运行程序的一个抽象,操作系统的其他所有内容都是围绕进程的概念展开的.所以想要真正了解进程,必须事先了解操作系统,egon介 ...

  4. 【Python】进程和线程

    多进程 多线程 ThreadLocal 进程vs线程 分布式进程 Top 学习廖老师的py官网的笔记 多任务的实现方式有三种方式: 1.多进程 2.多线程 3.多进程+多线程(这种比较复杂,实际很少采 ...

  5. Python语法进阶(1)- 进程与线程编程

    1.进程与多进程 1.1.什么是进程 进程就是程序执行的载体 什么叫多任务? 多任务就是操作系统可以同时运行多个任务.比如你一边在用浏览器学习,还一边在听音乐,,这就是多任务,至少同时有3个任务正在运 ...

  6. 进程和线程(4)-进程 vs. 线程

    进程 vs. 线程 我们介绍了多进程和多线程,这是实现多任务最常用的两种方式.现在,我们来讨论一下这两种方式的优缺点. 首先,要实现多任务,通常我们会设计Master-Worker模式,Master负 ...

  7. Linux的进程、线程、文件描述符是什么

    说到进程,恐怕面试中最常见的问题就是线程和进程的关系了,那么先说一下答案:在 Linux 系统中,进程和线程几乎没有区别. Linux 中的进程就是一个数据结构,看明白就可以理解文件描述符.重定向.管 ...

  8. Python 3 并发编程多进程之进程与线程

    Python 3 进程与线程 进程即正在执行的一个过程.进程是对正在运行程序的一个抽象. 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一.操作系统的 ...

  9. 进程,线程,以及Python的多进程实例

    什么是进程,什么是线程? 进程与线程是包含关系,进程包含了线程. 进程是系统资源分配的最小单元,线程是系统任务执行的最小单元. 打个比方,打开word,word这个程序是一个进程,里面的拼写检查,字数 ...

随机推荐

  1. 11892 - ENimEN(博弈)

    UVA 11892 - ENimEN 题目链接 题意:给定n堆石头.两人轮流取,每次仅仅能取1堆的1到多个.假设上一个人取了一堆没取完.那么下一个人必须继续取这堆.取到最后一个石头的赢,问谁赢 思路: ...

  2. (转)C系程序员面试必知必会之大端小端

      C程序员经常被问及的一道面试题是:什么是大端/小端,怎么样判断是大端/小端?大端小端问题对于嵌入式程序员绝对不会陌生(否则,别告诉我你是搞嵌入式的),它与CPU体系结构有关.比如常见的X86处理器 ...

  3. SQL面试练习(MySql)

    创建测试数据库: /*如果已经存在此数据库,先删除*/ drop database if exists sqltest ; /*创建并设置编码为UTF-8*/ create database sqlt ...

  4. WPF数据验证(5)―― 错误模板

    <Style TargetType="{x:Type TextBox}">            <Setter Property="Validatio ...

  5. Spark学习笔记:(一)入门 glance

    参考: http://spark.apache.org/docs/latest/quick-start.html 其它资料:    http://mojijs.com/2015/04/190845/i ...

  6. LeetCode题解(20)--Valid Parentheses

    https://leetcode.com/problems/valid-parentheses/ 原题: Given a string containing just the characters ' ...

  7. subclassdlgitem

    subclassdlgitem 该函数用来子类化一个控件. Subclass(子类化)是MFC中最常用的窗体技术之一.子类化完成两个工作:一是把窗体类对象attach到一个windows窗体实体中(即 ...

  8. 2016/05/25 抽象类与API(接口)差别

    简单来说, 接口是公开的,里面不能有私有的方法或变量,是用于让别人使用的,而抽象类是可以有私有方法或私有变量的, 另外,实现接口的一定要实现接口里定义的所有方法,而实现抽象类可以有选择地重写需要用到的 ...

  9. Codeforces Round #422 (Div. 2) C. Hacker, pack your bags! 排序,贪心

    C. Hacker, pack your bags!     It's well known that the best way to distract from something is to do ...

  10. POJ 3279 Dungeon Master

    Dungeon Master Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 21242   Accepted: 8265 D ...