美文网首页
Python 协程学习

Python 协程学习

作者: vckah | 来源:发表于2018-07-11 10:19 被阅读0次

协程本质上仍然是一个线程,其能够在多个任务之间切换来节省一些 IO 时间。

def consumer():
    while True:
        x = yield
        print("处理了数据")
def producer():
    c = consumer()
    next(c)
    for i in range(10):
        print("生产了数据:", i)
        c.send(i)
producer()
# 一边生产一边消耗,它并不能节省时间

greenlet 模块来支持

from greenlet import greenlet
def eat():
    print('eating start')
    g2.switch()
    print('eating end')

def play():
    print('playing start')
    g1.switch()
    print('playing end')
    g2.switch()

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

协程一般是为了规避 IO 时间的,对于计算型的,它并不能减少时间。一个线程最多可以起 500 个协程。
gevent 是一个支持协程的模块。gevent 的优势在于:用同步的方法来写异步的代码。一句话来阐述:使用 IO 多路复用对文件描述符的事件进行监听,从而使协程透明切换。

from gevent import monkey
monkey.patch_all()   <<--- 注意这个猴子补丁,它捕获程序中的 IO 时间,遇到会自动切换
import time
import gevent
def eat():
    print('eating start')
    time.sleep(1)
    print('eating end')

def play():
    print('playing start')
    time.sleep(1)
    print('playing end')

g1 = gevent.spawn(eat)
g2 = gevent.spawn(play)
g1.join()
g2.join()
# 可以查看它的线程名,发现它的名字是 DummyThread-1
# g.join(g_lst)

一般用在爬虫中。协程实现一个 socket 服务端

from gevent import monkey
monkey.patch_all()
import socket
import gevent

def talk(conn):
    conn.send(b'hellow')
    print(conn.recv(1024).decode('utf-8'))
    conn.close()
sk = socket.socket()
sk.bind(('127.0.0.1', 8000))
sk.listen()
while True:
    conn, addr = sk.accept()
    gevent.spawn(talk, conn)

gevent 提供了事件,感觉与线程的那个事件差不多:

import gevent
from gevent import Event

evt = Event()

def setter():
    print('wait for me')
    gevent.sleep(3)
    print('done')
    evt.set()

def waiter():
    print('wait...')
    evt.wait()
    print('finist')
gevent.joinall(
    [
        gevent.spawn(setter),
        gevent.spawn(waiter),
        gevent.spawn(waiter),
        gevent.spawn(waiter),
    ]
)

结果:

wait for me
wait...
wait...
wait...
done
finist
finist
finist

还有一个 AsyncResult 事件,用于在唤醒时传递消息。

from gevent.event import AsyncResult
aevt = AsyncResult()

def setter():
    print('wait ')
    gevent.sleep(3)  # 3秒后唤醒所有在evt上等待的协程
    print('done')
    aevt.set('hello') # 唤醒,并传递消息

def waiter():
    print("I‘ll wait for you")
    message = aevt.get()  # 等待,并在唤醒时获取消息
    print("Got wake up message: %s"% message)
gevent.joinall(
    [
        gevent.spawn(setter),
        gevent.spawn(waiter),
        gevent.spawn(waiter),
        gevent.spawn(waiter),
    ]
)

结果:

wait 
I‘ll wait for you
I‘ll wait for you
I‘ll wait for you
done
Got wake up message: hello
Got wake up message: hello
Got wake up message: hello

gevent 提供了一个队列对象,可以在协程之间安全的访问

import gevent
from gevent.queue import Queue

products = Queue()

def consumer(name):
    while not products.empty():
        print("%s got product % s"% (name, products.get()))
        gevent.sleep(0)

    print("%s quit"% name)

def producer():
    for i in range(1, 10):
        products.put(i)
gevent.joinall([
    gevent.spawn(producer),
    gevent.spawn(consumer, 'steve'),
    gevent.spawn(consumer, 'john'),
    gevent.spawn(consumer, 'nancy'),
])

结果:

steve got product 1
john got product 2
nancy got product 3
steve got product 4
john got product 5
nancy got product 6
steve got product 7
john got product 8
nancy got product 9
steve quit
john quit
nancy quit

还有一个 BoundedSemaphore 计数信号量:

import gevent
from gevent.lock import BoundedSemaphore

sem = BoundedSemaphore(2)

def worker(n):
    sem.acquire()
    print('Worker %i acquired semaphore' % n)
    gevent.sleep(2)
    sem.release()
    print('Worker %i released semaphore' % n)

gevent.joinall([gevent.spawn(worker, i) for i in range(0, 6)])

结果:

Worker 0 acquired semaphore
Worker 1 acquired semaphore
Worker 0 released semaphore
Worker 1 released semaphore
Worker 2 acquired semaphore
Worker 3 acquired semaphore
Worker 2 released semaphore
Worker 3 released semaphore
Worker 4 acquired semaphore
Worker 5 acquired semaphore
Worker 4 released semaphore
Worker 5 released semaphore

协程的本地变量:

import gevent
from gevent.local import local

data = local()

def f1():
    data.x = 1
    print(data.x)

def f2():
    try:
        print(data.x)
    except AttributeError:
        print('x is not visible')

gevent.joinall([
    gevent.spawn(f1),
    gevent.spawn(f2)
])

结果:

1
x is not visible

本地变量,当一个协程在内部使用了 data 对象后,那么它就在其它协程内不可见了。

相关文章

  • Python 协程

    仅供学习,转载请注明出处 协程 协程,又称微线程,纤程。英文名Coroutine。 协程是啥 协程是python个...

  • python异步协程(aiohttp,asyncio)

    python异步协程 环境:python3.7.0 协程 协程,英文叫做 Coroutine,又称微线程,纤程,协...

  • Python 协程的基本概念

    Python 协程的基本概念 在学习 Python 基础的过程中,遇到了比较难理解的地方,那就是协程。刚开始看了廖...

  • asyncio + asyncio 异步编程实例

    协程用法 接下来,我们来了解下协程的实现,从 Python 3.4 开始,Python 中加入了协程的概念,但这个...

  • Python 协程学习

    协程本质上仍然是一个线程,其能够在多个任务之间切换来节省一些 IO 时间。 greenlet 模块来支持 协程一般...

  • 协程

    1.协程 协程,又称微线程,纤程。英文名Coroutine。 1.1 协程是什么 协程是python个中另外一种实...

  • Python并发编程——协程

    摘要:Python,协程,gevent 协程基本概念 协程,又称微线程,纤程。英文名Coroutine,是Pyth...

  • 协程介绍

    协程 协程,又称微线程,纤程。英文名Coroutine。 1.协程是什么? 协程是python个中另外一种实现多任...

  • 4-7

    协程 协程,又称微线程,纤程。英文名Coroutine。 协程是啥 协程是python个中另外一种实现多任务的方式...

  • 协程

    协程 协程,又称微线程,纤程。英文名Coroutine。 协程是啥 协程是python个中另外一种实现多任务的方式...

网友评论

      本文标题:Python 协程学习

      本文链接:https://www.haomeiwen.com/subject/iubcpftx.html