Fluent Python

使用 asyncio 包处理并发

2018-03-20  本文已影响108人  一块大番薯

并发与并行(Concurrency、Parallelism)

asyncio 包

使用线程实现并发(threading 模块)

Python 没有提供终止线程的 API,所以要关闭线程,必须给线程发送信息
此处利用 signal.go 属性,从外部控制线程。

import sys
import time
import threading
import itertools


class Signal:
    go = True


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))  # 使用退格符(\x08)把光标移回来
        time.sleep(.1)
        if not signal.go:
            break
    write(' ' * len(status) + '\x08' * len(status)) 


def slow_func():
    time.sleep(3)
    return 42


def supervisor():
    signal = Signal()
    spinner = threading.Thread(target=spin,
                               args=('thinking!', signal))
    print('spinner object:', spinner)
    spinner.start()
    result = slow_func()
    signal.go = False
    spinner.join()  # 等待 spinner 线程结束
    return result


def main():
    result = supervisor()
    print('Answer:', result)


if __name__ == '__main__':
    main()

使用协程实现并发(asyncio 模块)

import sys
import asyncio
import itertools


@asyncio.coroutine
def spin(msg):
    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)  # 协程 asyncio.sleep 通过 yield from 调用
        except asyncio.CancelledError:
            break
    write(' ' * len(status) + '\x08' * len(status))


@asyncio.coroutine
def slow_func():
    yield from asyncio.sleep(3) # 把控制权交给主循环
    return 42


@asyncio.coroutine
def supervisor():
    spinner = asyncio.async(spin('thinking!')) # 协程 spin 通过 asyncio.async 调用
    print('spinner object:', spinner)  # Task 对象,类似 Thread 对象
    result = yield from slow_func()  # 协程 slow_func 通过 yield from 调用
    spinner.cancel()
    return result


def main():
    loop = asyncio.get_event_loop()
    result = loop.run_until_complete(supervisor())  # 驱动协程
    loop.close()
    print('Answer:', result)


if __name__ == '__main__':
    main()

对比线程和协程:

def supervisor():
    signal = Signal()
    spinner = threading.Thread(target=spin,
                               args=('thinking!', signal))
    print('spinner object:', spinner)
    spinner.start()
    result = slow_func()
    signal.go = False
    spinner.join()  
    return result

@asyncio.coroutine
def supervisor():
    spinner = asyncio.async(spin('thinking!')) 
    print('spinner object:', spinner)
    result = yield from slow_func()  
    spinner.cancel()
    return result
上一篇下一篇

猜你喜欢

热点阅读