Python之使用asyncio包处理并发

18.1 线程与协程对比

首先,分析spinner_thread.py脚本。

# -*- coding:utf-8 -*-

import threading
import itertools
import time
import sys


class Signal:#这个类定义一个简单的可变对象:其中有个go属性,用于从外部控制线程
    go = True


def spin(msg, signal):#这个函数会在单独的线程内运行。signal参数是前面定义的Signal类的实例
    write, flush = sys.stdout.write, sys.stdout.flush
    for char in itertools.cycle('|/-\\'):#这其实是个无限循环,因为itertools.cycle函数会在指定的序列中反复不断地生成元素
        status = char + ' ' + msg
        write(status)
        flush()
        write('\x08' * len(status))#这是显示文本式动画的诀窍所在:使用退格符('\x08')把光标移回来
        time.sleep(.1)
        if not signal.go:
            break
    write(' '*len(status) + '\x08'*len(status))#使用空格清楚状态信息,把光标移回开头
def slow_function():#假设这是耗时的计算
    #假装等待I/O一段时间
    time.sleep(3)#调用sleep函数阻塞会主线程,不过一定要这么做,以便释放GIL,创建从属线程
    return 42
def supervisor():#这个函数设置从属线程,显示线程对象,运行耗时的计算,最后杀死线程
    signal = Signal()
    spinner = threading.Thread(target=spin,args=("thinking!",signal))
    print('spinner object:', spinner)#显示从属线程对象
    spinner.start()#启动从属线程
    result = slow_function()#运行slow_function函数,阻塞主线程。同时从属线程以动画形式显示旋转指针
    signal.go = False#改变signal的状态;这会终止spin函数中的for循环
    spinner.join()#等待spinner线程结束
    return result
def main():
    result = supervisor()#运行supervisor函数
    print('Answer:', result)
if __name__=='__main__':
    main()

使用@asyncio.coroutine装饰器替代线程,实现相同的行为。

# -*- coding:utf-8 -*-
import asyncio
import itertools
import sys


@asyncio.coroutine#打算交给asyncio的线程要使用@asyncio.coroutine装饰,不是必须,但强烈建议
def spin(msg):#不需要signal参数
    write, flush = sys.stdout.write, sys.stdout.flush
    for char in itertools.cycle('|/-\\'):
        status = char + ' ' + msg
        write(status)
        flush()
        write('\x08' * len(status))
        try:
            yield from asyncio.sleep(.1)#代替time.sleep(.1),这样的休眠不会阻塞事件循环
        except asyncio.CancelledError:#如果spin函数苏醒后抛出该异常,其原因是发出了取消请求,因此退出循环
            break
    write(' ' * len(status) + '\x08' * len(status))


@asyncio.coroutine
def slow_function():#slow_function是协程,在用休眠假装进行I/O操作时,使用yield from继续执行事件循环。
    # 假装等待I/O一段时间
    yield from asyncio.sleep(3)#把控制权交给主循环,在休眠结束后恢复这个协程
    return 42


@asyncio.coroutine#打算
def supervisor():
    spinner = asyncio.async(spin('thinking!'))
    print('spinner object:', spinner)
    result = yield from slow_function()#驱动slow_function函数。结束后,获取返回值。同时事件继续运行,因为slow_funcion函数最后使用yield from asyncio.sleep(3)把控制权交给了主循环
    spinner.cancel()
    return result


def main():
    loop = asyncio.get_event_loop()#获取事件循环的引用
    result = loop.run_until_complete(supervisor())#驱动supervisor协程;这个协程的返回值是这次调用的返回值
    loop.close()
    print('Answer:', result)


if __name__ == '__main__':
    main()

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值