一 多进程multiprocessing

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.

import multiprocessing,time

def run(name):
print("hello",name)
time.sleep(2) if __name__ == '__main__': for i in range(10):
p = multiprocessing.Process(target=run,args=('Bob %s'%i,))
p.start()
import multiprocessing,time,threading

def thread_run():
print(threading.get_ident()) #线程号 def run(name):
print("hello",name)
t = threading.Thread(target=thread_run,)
t.start()
time.sleep() if __name__ == '__main__': for i in range():
p = multiprocessing.Process(target=run,args=('Bob %s'%i,))
p.start()

可以在进程中起线程

# 在主进程里调用了info,在子进程了又调用了info,我们看看效果?
# 可以看到,每一个进程都是由父进程启动的。主程序的父进程是pyCharm,子进程的父进程是主进程。 from multiprocessing import Process
import os def info(title):
print(title)
print('module name:', __name__)
print('parent process:', os.getppid()) #得到父进程ID
print('process id:', os.getpid()) #得到进程ID
print("\n\n") def f(name):
info('\033[31;1mfunction f\033[0m')
print('hello', name) if __name__ == '__main__':
info('\033[32;1mmain process line\033[0m')
p = Process(target=f, args=('bob',))
p.start()
p.join() #####输出:
####ain process line
####odule name: __main__
####arent process: 8268
####rocess id: 4448 ####unction f
####odule name: __mp_main__
####arent process: 4448
####rocess id: 9596 ####ello bob

得到进程ID

二 进程间通信

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

1.Queues

首先我们知道,线程之间是数据共享的,子线程放进queue数据,父线程可以取出来。如下示例

import threading,queue

def f():
q.put([42,None,'hello']) if __name__ == '__main__':
q = queue.Queue()
t = threading.Thread(target=f)
t.start()
print(q.get()) ####输出:[42, None, 'hello']

线程之间数据共享

把线程改为进程,会发现报错。

import multiprocessing,queue

def f():
q.put([42,None,'hello']) if __name__ == '__main__':
q = queue.Queue()
p = multiprocessing.Process(target=f)
p.start()
print(q.get()) ####输出报错:NameError: name 'q' is not defined

将线程改为进程,尝试数据传输,报错NameError: name 'q' is not defined

报错的原因是进程之间数据不共享。子进程和父进程分别拥有独立的内存空间,所以子进程是访问不了父进程的queue的。那有什么办法可以使子进程访问到父进程的queue呢?我们可以尝试将这个queue当做变量传给子进程。发现还是报错。

import multiprocessing,queue

def f(q):
q.put([42,None,'hello']) if __name__ == '__main__':
q = queue.Queue()
p = multiprocessing.Process(target=f,args=(q,))
p.start()
print(q.get()) ####输出报错:TypeError: can't pickle _thread.lock objects

将线程queue传递给子进程是不可以的,报错TypeError: can't pickle _thread.lock objects

报错的原因是我们错将线程queue(通过import queue引入)传递给了子进程,实际上我们传递给子进程的应该是进程queue(通过from multiprocessing import  Queue引入)。接下来才是正确的示例:

from multiprocessing import Process,Queue #引入进程queue

def f(q):
q.put([42,None,'hello']) #子进程放入数据 if __name__ == '__main__':
q = Queue()
p = Process(target=f,args=(q,)) #将q传递给子进程
p.start()
print(q.get()) #主进程取出数据 ####输出:[42, None, 'hello']

上面的例子,我们把进程queue传递给了子进程,表面上看,子进程和父进程共用一个queue,实际上并不是这样,而是子进程克隆了一个父进程的queue,子进程将数据放入克隆queue中,克隆queue将其序列化保存,然后进行反序列化后放到父进程的原始queue中,所以严格意义上子进程和父进程的queue并不是一个共享queue。

2.Pipes

要想实现两个进程间的数据传递,除了Queues,还可以使用Pipes。

Pipe()返回的两个连接对象代表管道的两端。 每个连接对象都有send()和recv()方法(以及其他方法)。

from multiprocessing import Process, Pipe

def f(conn):
conn.send([42, None, 'hello'])
print('from parent:',conn.recv())
conn.close() if __name__ == '__main__':
parent_conn, child_conn = Pipe()
p = Process(target=f, args=(child_conn,))
p.start()
print('from son:',parent_conn.recv())
parent_conn.send('hello')
p.join()

3.Managers

Queues和Pipes仅能实现两个进程之间的数据传递,而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 listdictNamespaceLockRLockSemaphoreBoundedSemaphoreConditionEventBarrierQueueValue and Array. For example,

from multiprocessing import Process, Manager
import os def f(d,l):
d[os.getpid()] = os.getpid()
l.append(os.getpid())
print(l) if __name__ == '__main__':
with Manager() as manager:
d = manager.dict() #生成一个字典,可在多个进程间共享和传递
l = manager.list(range(5)) #生成一个列表,可在多个进程间共享和传递
p_list = []
for i in range(10):
p = Process(target=f,args=(d,l))
p.start()
p_list.append(p)
for res in p_list: #等待结果
res.join() print(d)
[0, 1, 2, 3, 4, 8512]
[0, 1, 2, 3, 4, 8512, 11060]
[0, 1, 2, 3, 4, 8512, 11060, 4820]
[0, 1, 2, 3, 4, 8512, 11060, 4820, 9496]
[0, 1, 2, 3, 4, 8512, 11060, 4820, 9496, 4264]
[0, 1, 2, 3, 4, 8512, 11060, 4820, 9496, 4264, 8420]
[0, 1, 2, 3, 4, 8512, 11060, 4820, 9496, 4264, 8420, 9184]
[0, 1, 2, 3, 4, 8512, 11060, 4820, 9496, 4264, 8420, 9184, 6592]
[0, 1, 2, 3, 4, 8512, 11060, 4820, 9496, 4264, 8420, 9184, 6592, 9808]
[0, 1, 2, 3, 4, 8512, 11060, 4820, 9496, 4264, 8420, 9184, 6592, 9808, 5064]
{8512: 8512, 11060: 11060, 4820: 4820, 9496: 9496, 4264: 4264, 8420: 8420, 9184: 9184, 6592: 6592, 9808: 9808, 5064: 5064}

输出

进程锁

虽然进程之间是独立运行的,但是对于各进程来说,终端屏幕是共享的,为了防止输出结果时,各个进程争抢输出,造成打印结果混乱,可以给进程加一把锁。

from multiprocessing import Process,Lock

def f(l,i):
l.acquire() #得到锁
print("hello world",i)
l.release() #释放锁 if __name__ == '__main__':
lock = Lock() #生成锁的实例 for num in range(10):
Process(target=f,args=(lock,num)).start() #将lock传递给子进程

三 进程池

我们每起一个进程实际上就是克隆一份父进程数据给子进程使用,起多个进程时就会占用很多内存空间。为了节省开销,我们使用进程池。进程池就是限制同一时间有多少个进程运行。

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

进程池中有两个方法:

  • apply                #同步执行,即串行
  • apply_async     #异步执行,即并发
from multiprocessing import Pool
import time,os def Foo(i):
time.sleep(2)
print('my processid is ',os.getpid())
return i+100 if __name__ == '__main__': #windows上运行进程池必须加这行代码,否则报错
pool = Pool(5) #运行进程池中同时放入5个进程 for i in range(10):
# pool.apply(func=Foo,args=(i,)) #同步执行,即串行
pool.apply_async(func=Foo, args=(i,)) # 异步执行,即并发,此时有10个进程,同时执行的有5个,其他的挂起 print('end')
pool.close() #注意:一定要先关闭进程池再join
pool.join() #表示等进程池中进程执行完毕后称程序再关闭,如果注释,则程序直接关闭。

下面的例子,实现了主进程起了10个子进程,分别执行Foo函数,每次子进程执行完毕后,父进程回调Bar函数(可观察到执行Bar函数的进程ID与主进程ID相同)。

from multiprocessing import Pool
import time,os def Foo(i):
time.sleep(2)
print('my processid is ',os.getpid())
return i+100 def Bar(arg):
print('--exec done:',arg,'my processid is ',os.getpid()) if __name__ == '__main__': #windows上运行进程池必须加这行代码,否则报错
pool = Pool(5) #运行进程池中同时放入5个进程 for i in range(10):
pool.apply_async(func=Foo, args=(i,),callback=Bar) # callback=回调 print('end',os.getpid())
pool.close() #注意:先close再join
pool.join() #表示等进程池中进程执行完毕后称程序再关闭,如果注释,则程序直接关闭。

Python3学习之路~10.1 多进程、进程间通信、进程池的更多相关文章

  1. Python3学习之路~10.2 协程、Greenlet、Gevent

    一 协程 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切 ...

  2. Python3学习之路~10.3 论事件驱动与异步IO

    论事件驱动----详见:https://www.cnblogs.com/alex3714/articles/5248247.html Select\Poll\Epoll异步IO----详见:http: ...

  3. Python3学习之路~0 目录

    目录 Python3学习之路~2.1 列表.元组操作 Python3学习之路~2.2 简单的购物车程序 Python3学习之路~2.3 字符串操作 Python3学习之路~2.4 字典操作 Pytho ...

  4. springboot 学习之路 6(集成durid连接池)

    目录:[持续更新.....] spring 部分常用注解 spring boot 学习之路1(简单入门) spring boot 学习之路2(注解介绍) spring boot 学习之路3( 集成my ...

  5. python学习笔记——multiprocessing 多进程组件 进程池Pool

    1 进程池Pool基本概述 在使用Python进行系统管理时,特别是同时操作多个文件目录或者远程控制多台主机,并行操作可以节约大量时间,如果操作的对象数目不大时,还可以直接适用Process类动态生成 ...

  6. 2020.9.28 多进程multiprocess 进程池pool 子进程subprocess 进程间通信

    1.multiprocessing模块--跨平台版本的多进程模块 multiprocessing模块提供了一个Process类来代表一个进程对象,下面的例子演示了启动一个子进程并等待其结束: from ...

  7. Python 多进程和进程池

    一,前言 进程:是程序,资源集合,进程控制块组成,是最小的资源单位 特点:就对Python而言,可以实现真正的并行效果 缺点:进程切换很容易消耗cpu资源,进程之间的通信相对线程来说比较麻烦 线程:是 ...

  8. python多进程,进程池,数据共享,进程通信,分布式进程

    一.操作系统中相关进程的知识   Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊.普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前 ...

  9. python多进程,以及进程池并发

    模拟多进程 #!/usr/bin/env python#-*- coding:utf-8 -*-import timefrom multiprocessing import Process def s ...

随机推荐

  1. Maven和Ant简介以及两者的区别

    Maven 一.Maven简介 Maven是基于项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的软件项目管理工具. 目前,绝大多数开发人员都把 Ant 当作 Java 编程 ...

  2. C++全排列函数next_permutation()和prev_permutation()

    头文件:#include<algorithm> * * * 1. next_permutation(): next_permutation()函数的返回类型是bool类型. 即:如果有一个 ...

  3. 基于mykernel完成时间片轮询多道进程的简单内核

    基于mykernel完成时间片轮询多道进程的简单内核 原创作品转载请注明出处+中科大孟宁老师的linux操作系统分析:https://github.com/mengning/linuxkernel/ ...

  4. Y事业部打造一体化质量管理平台

    互联网企业质量管理的困惑 作为互联网时代的互联网企业,我们的研发模式和传统模式相比,最显著的不同在于发布节奏加快了,这个加快不是快了10%,20%,50%,而是加快了几倍,甚至几十倍,上百倍.面对加快 ...

  5. 正则表达式之RegExp对象

    1.定义 RegExp对象是原生JavaScript中表示正则表达式的对象:是正则表达式(regular expression)的简写.有一点需要明确知道,正则表达式只能对字符串进行操作. 2.语法 ...

  6. C#面向对象--属性

    一.属性(Property)作为类和结构的成员,是对字段的一种封装方式,实际上是一种特殊的方法,被称为访问器(Accessor),从而隐藏实现和验证代码,有助于提高字段读取和赋值的安全性和灵活性: 1 ...

  7. python爬虫之字体反爬

    一.什么是字体反爬? 字体反爬就是将关键性数据对应于其他Unicode编码,浏览器使用该页面自带的字体文件加载关键性数据,正常显示,而当我们将数据进行复制粘贴.爬取操作时,使用的还是标准的Unicod ...

  8. 【Mood】八上期末考

    Final exam  Day -30 平姐在班会上突然就说了一句,离期末考只有一个月了. 刚从体育节的气氛中脱离出来的我想了想,好像还真的是诶. 又努力地去想了想,好像不太慌张呢. Final ex ...

  9. boostrap3 bootstrap-datetimepicker.min.js设置中文语言

    问题 bootstrap3中使用bootstrap-datetimepicker遇到设置中文语言的问题 解决办法 bootstrap-datetimepicker在使用的时候要先引入momentjs中 ...

  10. js数组冒泡排序、快速排序、插入排序

    1.冒泡排序 //第一种 function bubblesort(ary){ for(var i=0;i<ary.length-1;i++){ for(var j=0;j<ary.leng ...