python并发编程之多进程、多线程、异步和协程详解

 更新时间:2016年10月28日 11:54:57   作者:tyomcat  
本篇文章详细的介绍了python并发编程之多进程、多线程、异步和协程,对初学python有一定的了解作用,需要的朋友可以参考下。

最近学习python并发,于是对多进程、多线程、异步和协程做了个总结。
一、多线程

多线程就是允许一个进程内存在多个控制权,以便让多个函数同时处于激活状态,从而让多个函数的操作同时运行。即使是单CPU的计算机,也可以通过不停地在不同线程的指令间切换,从而造成多线程同时运行的效果。

多线程相当于一个并发(concunrrency)系统。并发系统一般同时执行多个任务。如果多个任务可以共享资源,特别是同时写入某个变量的时候,就需要解决同步的问题,比如多线程火车售票系统:两个指令,一个指令检查票是否卖完,另一个指令,多个窗口同时卖票,可能出现卖出不存在的票。

在并发情况下,指令执行的先后顺序由内核决定。同一个线程内部,指令按照先后顺序执行,但不同线程之间的指令很难说清除哪一个会先执行。因此要考虑多线程同步的问题。同步(synchronization)是指在一定的时间内只允许某一个线程访问某个资源。

1、thread模块

2、threading模块
threading.Thread 创建一个线程。

给判断是否有余票和卖票,加上互斥锁,这样就不会造成一个线程刚判断没有余票,而另外一个线程就执行卖票操作。

#! /usr/bin/python
#-* coding: utf-8 -*
# __author__ ="tyomcat"
import threading
import time
import os

def booth(tid):
  global i
  global lock
  while True:
    lock.acquire()
    if i!=0:
      i=i-1
      print "窗口:",tid,",剩余票数:",i
      time.sleep(1)
    else:
      print "Thread_id",tid,"No more tickets"
      os._exit(0)
    lock.release()
    time.sleep(1)

i = 100
lock=threading.Lock()

for k in range(10):

  new_thread = threading.Thread(target=booth,args=(k,))
  new_thread.start()

二、协程(又称微线程,纤程)

协程,与线程的抢占式调度不同,它是协作式调度。协程也是单线程,但是它能让原来要使用异步+回调方式写的非人类代码,可以用看似同步的方式写出来。

1、协程在python中可以由生成器(generator)来实现。

首先要对生成器和yield有一个扎实的理解.

调用一个普通的python函数,一般是从函数的第一行代码开始执行,结束于return语句、异常或者函数执行(也可以认为是隐式地返回了None)。

一旦函数将控制权交还给调用者,就意味着全部结束。而有时可以创建能产生一个序列的函数,来“保存自己的工作”,这就是生成器(使用了yield关键字的函数)。

能够“产生一个序列”是因为函数并没有像通常意义那样返回。return隐含的意思是函数正将执行代码的控制权返回给函数被调用的地方。而"yield"的隐含意思是控制权的转移是临时和自愿的,我们的函数将来还会收回控制权。

看一下生产者/消费者的例子:

#! /usr/bin/python
#-* coding: utf-8 -*
# __author__ ="tyomcat"
import time
import sys
# 生产者
def produce(l):
  i=0
  while 1:
    if i < 10:
      l.append(i)
      yield i
      i=i+1
      time.sleep(1)
    else:
      return   
# 消费者
def consume(l):
  p = produce(l)
  while 1:
    try:
      p.next()
      while len(l) > 0:
        print l.pop()
    except StopIteration:
      sys.exit(0)
if __name__ == "__main__":
  l = []
  consume(l)

当程序执行到produce的yield i时,返回了一个generator并暂停执行,当我们在custom中调用p.next(),程序又返回到produce的yield i 继续执行,这样 l 中又append了元素,然后我们print l.pop(),直到p.next()引发了StopIteration异常。

2、Stackless Python

3、greenlet模块

基于greenlet的实现则性能仅次于Stackless Python,大致比Stackless Python慢一倍,比其他方案快接近一个数量级。其实greenlet不是一种真正的并发机制,而是在同一线程内,在不同函数的执行代码块之间切换,实施“你运行一会、我运行一会”,并且在进行切换时必须指定何时切换以及切换到哪。

4、eventlet模块

三、多进程
1、子进程(subprocess包)

在python中,通过subprocess包,fork一个子进程,并运行外部程序。

调用系统的命令的时候,最先考虑的os模块。用os.system()和os.popen()来进行操作。但是这两个命令过于简单,不能完成一些复杂的操作,如给运行的命令提供输入或者读取命令的输出,判断该命令的运行状态,管理多个命令的并行等等。这时subprocess中的Popen命令就能有效的完成我们需要的操作

>>>import subprocess
>>>command_line=raw_input()
ping -c 10 www.baidu.com
>>>args=shlex.split(command_line)
>>>p=subprocess.Popen(args)

利用subprocess.PIPE将多个子进程的输入和输出连接在一起,构成管道(pipe):

import subprocess
child1 = subprocess.Popen(["ls","-l"], stdout=subprocess.PIPE)
child2 = subprocess.Popen(["wc"], stdin=child1.stdout,stdout=subprocess.PIPE)
out = child2.communicate()
print(out)

communicate() 方法从stdout和stderr中读出数据,并输入到stdin中。

2、多进程(multiprocessing包)

(1)、multiprocessing包是Python中的多进程管理包。与threading.Thread类似,它可以利用multiprocessing.Process对象来创建一个进程。

进程池 (Process Pool)可以创建多个进程。

apply_async(func,args)  从进程池中取出一个进程执行func,args为func的参数。它将返回一个AsyncResult的对象,你可以对该对象调用get()方法以获得结果。

close()  进程池不再创建新的进程

join()   wait进程池中的全部进程。必须对Pool先调用close()方法才能join。

#! /usr/bin/env python
# -*- coding:utf-8  -*-
# __author__ == "tyomcat"
# "我的电脑有4个cpu"

from multiprocessing import Pool
import os, time

def long_time_task(name):
  print 'Run task %s (%s)...' % (name, os.getpid())
  start = time.time()
  time.sleep(3)
  end = time.time()
  print 'Task %s runs %0.2f seconds.' % (name, (end - start))

if __name__=='__main__':
  print 'Parent process %s.' % os.getpid()
  p = Pool()
  for i in range(4):
    p.apply_async(long_time_task, args=(i,))
  print 'Waiting for all subprocesses done...'
  p.close()
  p.join()
  print 'All subprocesses done.'

(2)、多进程共享资源

通过共享内存和Manager对象:用一个进程作为服务器,建立Manager来真正存放资源。

其它的进程可以通过参数传递或者根据地址来访问Manager,建立连接后,操作服务器上的资源。

#! /usr/bin/env python
# -*- coding:utf-8  -*-
# __author__ == "tyomcat"

from multiprocessing import Queue,Pool
import multiprocessing,time,random

def write(q):

  for value in ['A','B','C','D']:
    print "Put %s to Queue!" % value
    q.put(value)
    time.sleep(random.random())


def read(q,lock):
  while True:
    lock.acquire()
    if not q.empty():
      value=q.get(True)
      print "Get %s from Queue" % value
      time.sleep(random.random())
    else:
      break
    lock.release()

if __name__ == "__main__":
  manager=multiprocessing.Manager()
  q=manager.Queue()
  p=Pool()
  lock=manager.Lock()
  pw=p.apply_async(write,args=(q,))
  pr=p.apply_async(read,args=(q,lock))
  p.close()
  p.join()
  print
  print "所有数据都写入并且读完"

四、异步

无论是线程还是进程,使用的都是同步进制,当发生阻塞时,性能会大幅度降低,无法充分利用CPU潜力,浪费硬件投资,更重要造成软件模块的铁板化,紧耦合,无法切割,不利于日后扩展和变化。

不管是进程还是线程,每次阻塞、切换都需要陷入系统调用(system call),先让CPU跑操作系统的调度程序,然后再由调度程序决定该跑哪一个进程(线程)。多个线程之间在一些访问互斥的代码时还需要加上锁,

现下流行的异步server都是基于事件驱动的(如nginx)。

异步事件驱动模型中,把会导致阻塞的操作转化为一个异步操作,主线程负责发起这个异步操作,并处理这个异步操作的结果。由于所有阻塞的操作都转化为异步操作,理论上主线程的大部分时间都是在处理实际的计算任务,少了多线程的调度时间,所以这种模型的性能通常会比较好。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • python求两个时间的时间差(实例代码)

    python求两个时间的时间差(实例代码)

    我们在用python进行分析的时候,可能会碰到计算两个日期的时间差。下面为大家介绍一下如何计算两个时间的时间差,需要的朋友可以参考下
    2022-11-11
  • Python使用itertools模块实现排列组合功能示例

    Python使用itertools模块实现排列组合功能示例

    这篇文章主要介绍了Python使用itertools模块实现排列组合功能,涉及Python基于itertools模块product、permutations与combinations_with_replacement方法进行排列、组合等相关操作实现技巧,需要的朋友可以参考下
    2018-07-07
  • Python设计模式之策略模式实例详解

    Python设计模式之策略模式实例详解

    这篇文章主要介绍了Python设计模式之策略模式,结合实例形式分析了策略模式的概念、原理并结合实例形式分析了Python定义与使用策略模式相关操作技巧,需要的朋友可以参考下
    2019-01-01
  • python利用datetime模块计算程序运行时间问题

    python利用datetime模块计算程序运行时间问题

    这篇文章主要介绍了python利用datetime模块计算程序运行时间,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-02-02
  • python简单实现整数反转的画解算法

    python简单实现整数反转的画解算法

    这篇文章主要介绍了python简单实现整数反转采用了一个有趣的画解算法,通过示例的题目描述来对问题分析进行方案的解决,有需要的朋友可以参考下
    2021-08-08
  • Python绘图系统之自定义一个坐标列表控件

    Python绘图系统之自定义一个坐标列表控件

    这篇文章主要为大家详细介绍了Python如何编写一个绘图系统,可以实现自定义一个坐标列表控件,文中的示例代码讲解详细,感兴趣的可以了解一下
    2023-08-08
  • Python基础入门之if判断语句

    Python基础入门之if判断语句

    Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块,下面这篇文章主要给大家介绍了关于Python基础入门之if判断语句的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2021-09-09
  • python用folium绘制地图并设置弹窗效果

    python用folium绘制地图并设置弹窗效果

    这篇文章主要介绍了python用folium绘制地图并设置弹窗,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09
  • Pyside2中嵌入Matplotlib的绘图的实现

    Pyside2中嵌入Matplotlib的绘图的实现

    这篇文章主要介绍了Pyside2中嵌入Matplotlib的绘图的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-02-02
  • Python3中的循环语句示例详解

    Python3中的循环语句示例详解

    这篇文章主要介绍了Python3 循环语句,本文将详细介绍Python3中的循环语句,给出各种循环的使用示例,以及运行结果的解释,需要的朋友可以参考下
    2023-04-04

最新评论