Python并发编程-多进程

                       作者:尹正杰

版权声明:原创作品,谢绝转载!否则将追究法律责任。

一.多进程相关概念

  由于Python的GIL全局解释器锁存在,多线程未必是CPU密集型程序的好的选择。

  多进程可以完全独立的进程环境中运行程序,可以较充分地利用多处理器。

  但是进程本身的隔离带来的数据不共享也是一个问题。而且线程比进程轻量级。

二.multiprocessing

 #!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie import multiprocessing
import datetime """
  Process类遵循了Thread类的API,减少了学习难度。   相比线程的方法,进程多出来几个方法需要注意下:
    pid:
      进程id
    exitcode:
      进程的退出状态码
    terminate():
      终止指定的进程 先看一个例子,前面介绍的单线程、多线程比较的例子的多进程版本,具体代码如下所示。
""" def calc(i):
sum = 0
for _ in range(1000000000):
sum += 1
return i,sum if __name__ == '__main__':
start = datetime.datetime.now() ps = [] for i in range(4):
p = multiprocessing.Process(target=calc,args=(i,),name="calc-{}".format(i))
ps.append(p)
p.start() for p in ps:
p.join()
print(p.name,p.exitcode) delta = (datetime.datetime.now() - start).total_seconds()
print(delta) for p in ps:
print(p.name,p.exitcode) print("=== end ===")
calc-
calc-
calc-
calc-
47.011848
calc-
calc-
calc-
calc-
=== end ===

以上代码执行结果戳这里

三.进程间同步

  Python在进程间同步提供了和线程同步一样的类,使用的方法一样,使用的效果也类似。

  不过,进程间代价要高于线程间,而且系统底层实现是不同的,只不过Python屏蔽了这些不同之处,让用户简单使用多进程。
  multiprocessing还提供共享内存、服务器进程来共享数据,还提供了用于进程间通讯的Queue队列,Pipe管道。

  通信方式不同
    .多进程就是启动多个解释器进程,进程间通信必须序列化、反序列化
    .数据的线程安全性问题

  如果每个进程中没有实现多线程,即每个进程仅有一个线程,此时GIL可以说没什么用了。

四.进程池举例

1>.multiprocessing.Pool 是进程池类

multiprocessing.Pool 是进程池类,他有很多方法,具体如下:
  apply(self, func, args=(), kwds={}):
    阻塞执行,导致主进程执行其他子进程就像一个个执行

  apply_async(self, func, args=(), kwds={},callback=None, error_callback=None):
    与apply方法用法一致,非阻塞异步执行,得到结果后会执行回调

  close():
    关闭池,池不能再接受新的任务,所有任务完成后退出进程

  terminate():
    立即结束工作进程,不再处理未处理的任务
  
  join():
    主进程阻塞等待子进程的退出, join方法要在close或terminate之后使用

2>.同步调用

 #!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie import logging
import datetime
import multiprocessing
# 日志打印进程id、进程名、线程id、线程名
logging.basicConfig(level=logging.INFO, format="%(process)d %(processName)s %(thread)d %(message)s")
def calc(i):
sum = 0
for _ in range(1000000000): # 10亿
sum += 1
logging.info(sum)
return i,sum # 进程要return,才可以拿到这个结果 if __name__ == '__main__': # 注意一定要有这一句
start = datetime.datetime.now() pool = multiprocessing.Pool(4) for i in range(4):
# 返回值,同步调用,注意观察CPU使用
ret = pool.apply(calc, args=(i,))
print(ret)
pool.close()
pool.join() delta = (datetime.datetime.now() - start).total_seconds()
print(delta)
print('===end====')
calc-0 0
calc-1 0
calc-2 0
calc-3 0
50.399442
calc-0 0
calc-1 0
calc-2 0
calc-3 0
=== end ===

以上代码执行结果戳这里

3>.异步调用

 #!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie import logging
import datetime
import multiprocessing
# 日志打印进程id、进程名、线程id、线程名
logging.basicConfig(level=logging.INFO, format="%(process)d %(processName)s %(thread)d %(message)s") def calc(i):
sum = 0
for _ in range(1000000000): # 10亿
sum += 1
logging.info(sum)
return i, sum # 进程要return,callback才可以拿到这个结果 if __name__ == '__main__':
start = datetime.datetime.now() # 注意一定要有这一句
pool = multiprocessing.Pool(4)
for i in range(4):
# 异步拿到的返回值是什么?
ret = pool.apply_async(calc, args=(i,))
print(ret, '~~~~~~~') # 异步,如何拿到真正的结果呢?
pool.close()
pool.join()
delta = (datetime.datetime.now() - start).total_seconds()
print(delta)
print('===end====')
<multiprocessing.pool.ApplyResult object at 0x000001F02D3230C8> ~~~~~~~
<multiprocessing.pool.ApplyResult object at 0x000001F02D3231C8> ~~~~~~~
<multiprocessing.pool.ApplyResult object at 0x000001F02D323308> ~~~~~~~
<multiprocessing.pool.ApplyResult object at 0x000001F02D3233C8> ~~~~~~~
5828 SpawnPoolWorker-4 7608 1000000000
7248 SpawnPoolWorker-3 5168 1000000000
2020 SpawnPoolWorker-1 2252 1000000000
1620 SpawnPoolWorker-2 3128 1000000000
47.058129
===end====

以上代码执行结果

4>.异步调用,拿最终结果

 #!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie import logging
import datetime
import multiprocessing # 日志打印进程id、进程名、线程id、线程名
logging.basicConfig(level=logging.INFO, format="%(process)d %(processName)s %(thread)d %(message)s") def calc(i):
sum = 0
for _ in range(1000000000): # 10亿
sum += 1
logging.info(sum)
return i, sum # 进程要return,callback才可以拿到这个结果 if __name__ == '__main__':
start = datetime.datetime.now() # 注意一定要有这一句 pool = multiprocessing.Pool(4) for i in range(4):
#异步拿到的返回值是什么?回调起了什么作用?
ret = pool.apply_async(calc, args=(i,),callback=lambda ret: logging.info('{} in callback'.format(ret)))
print(ret, '~~~~~~~') pool.close()
pool.join()
delta = (datetime.datetime.now() - start).total_seconds()
print(delta)
print('===end====')
<multiprocessing.pool.ApplyResult object at 0x0000017D9709F308> ~~~~~~~
<multiprocessing.pool.ApplyResult object at 0x0000017D9709F448> ~~~~~~~
<multiprocessing.pool.ApplyResult object at 0x0000017D9709F508> ~~~~~~~
<multiprocessing.pool.ApplyResult object at 0x0000017D9709F5C8> ~~~~~~~
8964 SpawnPoolWorker-1 1620 1000000000
572 MainProcess 8184 (0, 1000000000) in callback
992 SpawnPoolWorker-2 2484 1000000000
572 MainProcess 8184 (1, 1000000000) in callback
10608 SpawnPoolWorker-3 2404 1000000000
572 MainProcess 8184 (2, 1000000000) in callback
3268 SpawnPoolWorker-4 8684 1000000000
572 MainProcess 8184 (3, 1000000000) in callback
44.991332
===end====

以上代码执行结果戳这里

五.多进程、多线程的选择

1>.CPU密集型

  CPython中使用到了GIL,多线程的时候锁相互竞争,且多核优势不能发挥,选用Python多进程效率更高。

2>.IO密集型

  在Python中适合是用多线程,可以减少多进程间IO的序列化开销。且在IO等待的时候,切换到其他线程继续执行,效率不错。

3>.应用

请求/应答模型:WEB应用中常见的处理模型
  master启动多个worker工作进程,一般和CPU数目相同。发挥多核优势。
  worker工作进程中,往往需要操作网络IO和磁盘IO,启动多线程,提高并发处理能力。worker处理用户的请求,往往需要等待数据,处理完请求还要通过网络IO返回响应。
  这就是nginx工作模式。

六.Linux的特殊进程(在Linux/Unix中,通过父进程创建子进程。)

1>.僵尸进程

  一个进程使用了fork创建了子进程,如果子进程终止进入僵死状态,而父进程并没有调用wait或者waitpid获取子进程的状态信息,那么子进程仍留下一个数据结构保存在系统中,这种进程称为僵尸进程。

  僵尸进程会占用一定的内存空间,还占用了进程号,所以一定要避免大量的僵尸进程产生。有很多方法可以避免僵尸进程。

2>.孤儿进程

  父进程退出,而它的子进程仍在运行,那么这些子进程就会成为孤儿进程。孤儿进程会被init进程(进程号为1)收养,并由init进程对它们完成状态收集工作。

  init进程会循环调用wait这些孤儿进程,所以,孤儿进程没有什么危害。

3>.守护进程

  它是运行在后台的一种特殊进程。它独立于控制终端并周期性执行某种任务或等待处理某些事件。

  守护进程的父进程是init进程,因为其父进程已经故意被终止掉了。

  守护进程相对于普通的孤儿进程需要做一些特殊处理。

Python并发编程-多进程的更多相关文章

  1. python并发编程&多进程(二)

    前导理论知识见:python并发编程&多进程(一) 一 multiprocessing模块介绍 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_cou ...

  2. python并发编程&多进程(一)

    本篇理论居多,实际操作见:  python并发编程&多进程(二) 一 什么是进程 进程:正在进行的一个过程或者说一个任务.而负责执行任务则是cpu. 举例(单核+多道,实现多个进程的并发执行) ...

  3. python 并发编程 多进程 目录

    python multiprocessing模块 介绍 python 开启进程两种方法 python 并发编程 查看进程的id pid与父进程id ppid python 并发编程 多进程 Proce ...

  4. python 并发编程 多进程 队列目录

    python 并发编程 多进程 队列 python 并发编程 多进程 生产者消费者模型介绍 python 并发编程 多进程 生产者消费者模型总结 python 并发编程 多进程 JoinableQue ...

  5. python 并发编程 多进程 互斥锁 目录

    python 并发编程 多进程 互斥锁 模拟抢票 互斥锁与join区别

  6. python 并发编程 多进程 生产者消费者模型介绍

    一 生产者消费者模型介绍 为什么要使用生产者消费者模型 生产者指的是生产数据的任务,消费者指的是处理数据的任务, 生产数据目的,是为了给消费者处理. 在并发编程中,如果生产者处理速度很快,而消费者处理 ...

  7. python 并发编程-- 多进程

    一 multiprocessing 模块介绍 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大部分情况需要使用多进程 ...

  8. python 并发编程 多进程 互斥锁

    运行多进程  每个子进程的内存空间是互相隔离的 进程之间数据不能共享的 一 互斥锁 但是进程之间都是运行在一个操作系统上,进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终 ...

  9. Python并发编程-多进程socketserver简易版

    普通版的socketserver #server.py import socket sk = socket.socket() sk.bind(('127.0.0.1',8080))#建立连接 sk.l ...

随机推荐

  1. shell中函数的使用

    函数是一个脚本代码块,你可以对它进行自定义命名,并且可以在脚本中任意位置使用这个函数.如果想要这个函数,只要调用这个函数的名称就可以了.使用函数的好处在于模块化以及代码可读性强. (1).函数的创建语 ...

  2. [ kvm ] 三种基础网络模型创建及分析

    1. 前言 最近在模拟生产环境在做测试,本来准备用 vmware 直接来实现的,本着学以致用的道理,选择直接在linux 环境使用 kvm 来模拟测试,遇到的第一个问题就是,网络环境的模拟.这里对比v ...

  3. win7安装 nodejs,npm

    1. 下载地址:http://nodejs.org/dist/v9.7.1/ 2. 安装 3. 查看是否安装成功,命令行查询 node  -v 4. 默认已经安装了npm,直接查询版本 5. 配置np ...

  4. 向DataGrid数据表格增加查询搜索框

    向DataGrid数据表格增加查询搜索框 效果如下: js代码: $(function(){ var dg = $('#dg').datagrid({ url:"${pageContext. ...

  5. js中对字符串操作的常见方法(1)

    String类型 创建一个String类型的实例 var stringObject = new String("hello world"); String类型的属性 length; ...

  6. Python调用Matlab2014b引擎

    用惯Python的你,是不是早已无法忍受matplotlib那丑陋无比的图以及蛋疼无比部署依赖? 当当当当,Matlab2014b的Python Engine API现已加入豪华午餐. 上次写了一篇文 ...

  7. Golang ---基准测试

    什么是基准测试 基准测试,是一种测试代码性能的方法,比如你有多种不同的方案,都可以解决问题,那么到底是那种方案性能更好呢?这时候基准测试就派上用场了. 基准测试主要是通过测试CPU和内存的效率问题,来 ...

  8. NETRemoting学习笔记

    1..NET Remoting概念 1.一种分布式处理方式.从字面意义上看出,他是基于.net平台的一种远程对象开发技术,该技术是将远程计算机中的数据视为分布式对象来进行开发. 2.一种网络通信技术. ...

  9. java之hibernate之组合主键映射

    1.在应用中经常会有主键是由2个或多个字段组合而成的.比如成绩表: 第一种方式:把主键写为单独的类 2.类的设计:studentId,subjectId ,这两个主键是一个组件.所以可以采用组件映射的 ...

  10. SessionChange

    protected override void OnSessionChange(SessionChangeDescription changeDescription) { System.IO.File ...