设为首页 加入收藏

TOP

python --- 协程编程(第三方库gevent的使用)(一)
2017-11-20 08:34:56 】 浏览:371
Tags:python --- 编程 第三方 gevent 使用

1. 什么是协程?

  协程(coroutine),又称微线程。协程不是线程也不是进程,它的上下文关系切换不是由CPU控制,一个协程由当前任务切换到其他任务由当前任务来控制。一个线程可以包含多个协程,对于CPU而言,不存在协程这个概念,它是一种轻量级用户态线程(即只针对用户而言)。协程拥有自己的寄存器上下文和栈,协程调度切换到其他协程时,将寄存器上下文和栈保存,在切回到当前协程的时候,恢复先前保存的寄存器上下文和栈。

2. 在编程中为什么要使用协程?

  使用协程的好处:(1)CPU无需负担上下文的开销;(2)不需加锁(多个线程操作数据时得加锁);(3)由程序员切换控制流,方便编程;(4)高并发、高扩展、低成本(一个CPU支持上万的协程都不是问题)。

   当然,任何事物有优点必有缺点。协程得缺点:(1)协程自己无法利用CPU多核资源(除非与多进程或者多线程配合);(2)遇到阻塞操作会使整个程序阻塞。

 

例一(使用yield实现在任务间的切换):

 1 import time
 2 
 3 def func1(name):
 4     print("----func1 start...----")
 5     for i in range(6):
 6         temp = yield      #每次遇到yield,func1在此处阻塞,直到temp接收到func2中con.send()传来的值
 7         print("%s in the func1" % (str(temp)))
 8         time.sleep(1)
 9 
10 
11 def func2():
12     print("----func2 start...----")
13     con.__next__()     #此处开始真正的func1的调用
14     for i in range(5):
15         con.send(i+1)
16         print("%s in the func2" % i)
17 
18 
19 if __name__ == '__main__':
20     con = func1(1)     #在有yield的函数中此处不是真正的函数调用,打印con便可知道
21     # print(con)
22     p = func2()
使用yield进行任务切换

  注:例一严格来说不能算是协程,只是实现了两个任务之间的切换。

 

3. 既然例一不能算多协程,难么在python中应该如何使用协程?

  greenlet是一个用C实现的协程模块,相比与python自带的yield,它可以使你在任意函数之间随意切换,而不需把这个函数先声明为generator(例一中的con=func1(1)就是做这个操作)。

 

例二:

 1 import greenlet
 2 
 3 def func1():
 4     for i in range(1,6):
 5         print(i)
 6         g2.switch()   #切换到g2
 7 
 8 def func2():
 9     words = ['a', 'b', 'c', 'd', 'e']
10     for w in words:
11         print(w)
12         g1.switch()    #切换到g1
13 
14 g1 = greenlet.greenlet(func1)
15 g2 = greenlet.greenlet(func2)
16 g1.switch()   #切换到g1
使用greenlent模块实现任务切换

  注:使用greenlent可以很简单的进行多任务之间的切换,但是程序运行最耗时的便是I/O操作,要使用协程实现高并发,应当是一旦遇到I/O操作就切换到其他任务,等I/O操作完成后在切回到当前任务(这个过程应当是自动的)。

 

4. 那么在python中,如何让任务遇到I/O操作就切换?

  我们使用第三方库gevent来实现。

  gevent的官方定义:gevent is a coroutine -based Python networking library that uses greenlet to provide a high-level synchronous API on top of the libev event loop.

 

例三(gevent的简单使用):

 1 import gevent
 2 import time
 3 
 4 def func1():
 5     print("func1: start.....")
 6     # Put the current greenlet to sleep for at least *seconds*.(模拟I/O操作,任务在此处自动切换)
 7     gevent.sleep(3)
 8     print("func1: end")
 9 
10 def func2():
11     print("func2: start.....")
12     gevent.sleep(0.5)
13     print("func2: end")
14 
15 start_time = time.time()
16 # joinall(greenlets, timeout=None, raise_error=False, count=None)
17 # Wait for the ``greenlets`` to finish.
18 # :return: A sequence of the greenlets that finished before the timeout (if any)expired.
19 gevent.joinall([gevent.spawn(func1),
20                 gevent.spawn(func2)])
21 # spawn(cls, *args, **kwargs)
22 # Create a new :class:`Greenlet` object and schedule it to run ``function(*args, **kwargs)``.
23 # This can be used as ``gevent.spawn`` or ``Greenlet.spawn``.
24 
25 print("cost:", time.time()-start_time)
26 # 通过计算程序运行的时间可以发现程序确实是以单线程达模拟出了多任务并行的操作。
gevent的简单使用

 

例四(gevent和urllib配合同时下载多个网页):

 1 import urllib.request
 2 import gevent,time
 3 import gevent.monkey
 4 
 5 def func(url="", filename=""):
 6     print("Download:%s" % url)
 7     result = urllib.request.urlopen(url)       #请求打开一个网页
 8     data = result.read()     #读取内容
 9     with open(filename, 'wb') as fp:    #写入文档
10         fp.write(data)
11     print("Finish:%s" % url)
12 
13 if __name__ == "__main__":
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇python基础(1)---python简介 下一篇python基础(2)---数据类型

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目