码迷,mamicode.com
首页 > 其他好文 > 详细

并发之协程

时间:2019-01-04 21:31:44      阅读:163      评论:0      收藏:0      [点我收藏+]

标签:ons   code   response   mon   pen   print   阻塞   如何   效果   

协程 Coroutine

据说, python官方没有协程这个玩意儿 ,这是程序员自己鼓捣出来的, 更加轻量级(任务切换不是由自己的代码实现,而不是操作系统)
也叫微线程,  用这个可以让自己的程序对CPU 的占用率更高!避免被操作系统剥夺CPU的使用权.

对比操作系统控制线程的切换,用户在单线程内控制协程的切换

优点如下:

#1. 协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级
#2. 单线程内就可以实现并发的效果,最大限度地利用cpu

缺点如下:

#1. 协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协程
#2. 协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程

那么做到协程起码得实现以下两点:

1. 可以控制多个任务之间的切换,切换之前将任务的状态保存下来,以便重新运行时,可以基于暂停的位置继续执行。

2. 作为1的补充:可以检测IO操作,在遇到io操作的情况下才发生切换

那如何去实现呢?

对于 1 . 可以使用yield  但是yield 不能识别阻塞

技术分享图片
import time

def func1():
    while True:
        yield

def func2():
    g=func1()
    for i in range(10000000):
        i+1
        next(g)

start=time.time()
func2()
stop=time.time()
print(stop-start)
yield

如果我们在单个线程内有20个任务,要想实现在多个任务之间切换,使用yield生成器的方式过于麻烦(需要先得到初始化一次的生成器,然后再调用send。。。非常麻烦),而使用greenlet模块可以非常简单地实现这20个任务直接的切换(这是个第三方模块,需要自己安装)

技术分享图片
from greenlet import greenlet

def eat(name):
    print(%s eat 1 %name)
    g2.switch(egon)
    print(%s eat 2 %name)
    g2.switch()
def play(name):
    print(%s play 1 %name)
    g1.switch()
    print(%s play 2 %name)

g1=greenlet(eat)
g2=greenlet(play)

g1.switch(jerry) # 可以在第一次switch时传入参数,以后都不需要
greenlet

 但是以上两者都不能实现识别到阻塞,并在阻塞前切换到

别慌,肯定有办法的

技术分享图片
import gevent, time
from gevent import monkey  # 帮助监测程序自己的阻塞


def micro_thread1():
    print("thread1 run...")
    print(time.time())
    # gevent.sleep(2)# 可以检测到自己的阻塞
    monkey.patch_all()
    print("睡眠")
    time.sleep(1)  # 你以为你用的sleep 实际上间接用的 gevent里的sleep  点patch_all()进去看
    print("thread1 run...")


def micro_thread2():
    print(time.time())
    time.sleep(3)  # 模拟IO操作耗时   在IO的时候  micro_thread1 还在运行
    print("thread2 run...")


g1 = gevent.spawn(micro_thread1)
g2 = gevent.spawn(micro_thread2)

gevent.joinall([g1, g2])  # 以后就都这样写 便不会因为单独对象join()而出错 这里的join兼顾start() 而单独的start是没用的
gevent 与 monkey
技术分享图片
from gevent import monkey;

monkey.patch_all()
import gevent
import requests
import time


def get_page(url):
    print(GET: %s % url)
    response = requests.get(url)
    if response.status_code == 200:
        print(%d bytes received from %s % (len(response.text), url))


start_time = time.time()
gevent.joinall([
    gevent.spawn(get_page, https://www.python.org/),
    gevent.spawn(get_page, https://www.yahoo.com/),
    gevent.spawn(get_page, https://github.com/),
])
stop_time = time.time()
print(run time is %s % (stop_time - start_time))
在爬虫中的实例

 

 我们可以用threading.current_thread().getName()来查看每个g1和g2,查看的结果为DummyThread-n,即假线程

 

并发之协程

标签:ons   code   response   mon   pen   print   阻塞   如何   效果   

原文地址:https://www.cnblogs.com/guyanzhi/p/10222268.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!