设为首页 加入收藏

TOP

python网络-多任务实现之协程(一)
2019-05-24 20:07:58 】 浏览:170
Tags:python 网络 任务 实现

一、协程

协程,又称微线程,纤程。英文名Coroutine。

协程不是进程,也不是线程,它就是一个函数,一个特殊的函数——可以在某个地方挂起,并且可以重新在挂起处继续运行。所以说,协程与进程、线程相比,不是一个维度的概念。

一个进程可以包含多个线程,一个线程也可以包含多个协程,也就是说,一个线程内可以有多个那样的特殊函数在运行。但是有一点,必须明确,一个线程内的多个协程的运行是串行的。如果有多核CPU的话,多个进程或一个进程内的多个线程是可以并行运行的,但是一个线程内的多个协程却绝对串行的,无论有多少个CPU(核)。这个比较好理解,毕竟协程虽然是一个特殊的函数,但仍然是一个函数。一个线程内可以运行多个函数,但是这些函数都是串行运行的。当一个协程运行时,其他协程必须挂起。

通俗的理解:在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己确定

二、yield实现协程

 1 import time
 2 
 3 def A():
 4     while True:
 5         print("----A---")
 6         yield
 7         time.sleep(0.3)
 8 
 9 def B(c):
10     while True:
11         print("----B---")
12         next(c)
13         time.sleep(0.3)
14 
15 if __name__=='__main__':
16     a = A()
17     B(a)

执行结果

----B---
----A---
----B---
----A---
----B---
----A---
----B---
----A---
----B---
----A---
省略。。。

代码说明:

第17行:调用函数B,并把a传递进去。执行打印B的代码,代码执行到next(c)时,会调用函数A,执行打印A的代码,当代码实行带第6行遇到yield的实行,该协程进入等待状态,回到原来next(c)处继续执行,从而实现多协程的切换,通过yield关键字。

 

三、greenlet

1、greenlet实现多任务协程

为了更好使用协程来完成多任务,python中的greenlet模块对其封装,从而使得切换任务变的更加简单,在使用前先要确保greenlet模块安装

使用如下命令安装greenlet模块:

sudo pip install greenlet
#coding = utf-8
from greenlet import greenlet
def test1():
    print("1")
    gr2.switch()
    print("2")

def test2():
    print("3")
    gr1.switch()
    print("4")

gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()

运行结果:

1
3
2

当创建一个greenlet时,首先初始化一个空的栈, switch到这个栈的时候,会运行在greenlet构造时传入的函数(首先在test1中打印 1), 如果在这个函数(test1)中switch到其他协程(到了test2 打印3),那么该协程会被挂起,等到切换回来(在test1切换回来 打印2)。当这个协程对应函数执行完毕,那么这个协程就变成dead状态。
  

注意 上面没有打印test2的最后一行输出 4,因为在test2中切换到gr1之后挂起,但是没有地方再切换回来。

2、greenlet的模块与类

我们首先看一下greenlet这个module里面的属性

>>> import greenlet
>>> dir(greenlet)
['GREENLET_USE_GC', 'GREENLET_USE_TRACING', 'GreenletExit', '_C_API', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '__version__', 'error', 'getcurrent', 'gettrace', 'greenlet', 'settrace']

其中,比较重要的是getcurrent(), 类greenlet、异常类GreenletExit。

getcurrent()返回当前的greenlet实例;

GreenletExit:是一个特殊的异常,当触发了这个异常的时候,即使不处理,也不会抛到其parent(后面会提到协程中对返回值或者异常的处理)

然后我们再来看看greenlet.greenlet这个类:

>>>dir(greenlet.greenlet)
['GreenletExit', '__bool__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_stack_saved', 'dead', 'error', 'getcurrent', 'gettrace', 'gr_frame', 'parent', 'run', 'settrace', 'switch', 'throw']

比较重要的几个属性:

  run:当greenlet启动的时候会调用到这个callable,如果我们需要继承greenlet.greenlet时,需要重写该方法

  switch:前面已经介绍过了,在greenlet之间切换

  parent:可读写属性,后面介绍

  dead:如果greenlet执行结束,那么该属性为true

  throw:切换到指定greenlet后立即跑出异常

文章后面提到的greenlet大多都是指greenlet.greenlet这个class,请注意区别 

对于greenlet,最常用的写法是 x = gr.switch(y)。 这句话的意思是切换到gr,传入参数y。当从其他协程(不一定是这个gr)切换回来的时候,将值付给x。

import greenlet


def test1(x, y):
    z = gr2.switch(x + y)
    print("test1:%s" % z)


def test2(a):
    print('te
首页 上一页 1 2 3 4 5 下一页 尾页 1/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇python常用内置算法用到的单词音频 下一篇python3:判断手机的亮屏状态

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目