python线程与协程

协程与线程有什么区别,我觉得主要区别是:线程是操作系统来控制什么时候切换运行程序,而协程是程序员自己决定什么时候交出运行权。

一、线程

线程在任何编程语言中,都算是比较难的内容,python也不例外。先看看《流畅的python》书中的例子:

#win7+python3.7
import threading
import itertools
import time
import sys

def spin(msg, done):  # <2>
    write, flush = sys.stdout.write, sys.stdout.flush
    for char in itertools.cycle('|/-\\'):  # 无限循环依次输出符号
        status = char + ' ' + msg
        write(status)
        flush()
        write('\x08' * len(status))  # 退格键,实现动态效果
        if done.wait(.1):  # 等待0.1秒,如果内部标志为true,退出。0.1在这里表示速度。
            break
    write(' ' * len(status) + '\x08' * len(status))  # \x08表示退格符,是实现动态效果的关键

def slow_function():  # <7>
    # pretend waiting a long time for I/O
    time.sleep(3)  # <8>
    return 42

def supervisor():  # <9>
    done = threading.Event()#注意,采用的是threading,老的thread被废弃了
    spinner = threading.Thread(target=spin,args=('thinking!', done))
    print('spinner object:', spinner)  # <10>
    spinner.start()  # <11>
    result = slow_function()  # <12>
    done.set()  # 将Event的内部状态标志设为true
    spinner.join()  # <14>
    return result

def main():
    result = supervisor()  # <15>
    print('Answer:', result)

if __name__ == '__main__':
    main()

运行效果:

持续3秒后,返回结果:

(1)事件对象:threading.Event

一个事件对象管理一个内部标志,初始状态默认为False,set()方法可将它设置为True,clear()方法可将它设置为False,wait()方法将线程阻塞直到内部标志的值为True。

  • wait(timeout=None):阻塞线程直到内部标志为True,或者发生超时事件。如果调用时内部标志就是True,那么不会被阻塞,否则将被阻塞。timeout为浮点类型的秒数。

二、协程

#win7+python3.7
import asyncio
import itertools
import sys

@asyncio.coroutine  # <1>
def spin(msg):  # <2>
    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)  # <3>
        except asyncio.CancelledError:  # 下面的spinner.cancel()方法会抛出CancelledError异常
            break
    write(' ' * len(status) + '\x08' * len(status))

@asyncio.coroutine
def slow_function():  # <5>
    # pretend waiting a long time for I/O
    yield from asyncio.sleep(3)  # <6>
    return 42

@asyncio.coroutine
def supervisor():  # 监管员方法,因为调用协程方法的必须是协程或者loop,这个方法起一个程序流程的总控制作用
    spinner = asyncio.ensure_future(spin('thinking!'))  # 把spin协程包装成Task
    print('spinner object:', spinner)  # <9>
    result = yield from slow_function()  # <10>
    spinner.cancel()  # spinner任务被删除,抛出CancelledError异常
    return result

def main():
    loop = asyncio.get_event_loop()  # <12>
    result = loop.run_until_complete(supervisor())  # <13>
    loop.close()
    print('Answer:', result)

if __name__ == '__main__':
    main()

运行效果与上面的线程相似:

协程涉及到的新概念很多,在此讲几个最重要的:

  1. event_loop 事件循环:程序开启一个无限的循环,程序员会把一些函数注册到事件循环上。当满足事件发生的时候,调用相应的协程函数。
  2. coroutine 协程:协程对象,指一个使用async关键字定义的函数,它的调用不会立即执行函数,而是会返回一个协程对象。协程对象需要注册到事件循环(loop),由事件循环调用run_until_complete()运行。
  3. task 任务:可以理解为单个coroutine,经过ensure_future()方法处理而形成,而众多task所组成的集合经过asyncio.gather处理而形成一个future。。
  4. future: 代表将来执行或没有执行的任务。task是future的子类,future就是存放着众多task或future的容器。
  5. async/await 关键字:协程方法需要用@asyncio.coroutine注解、yield from,python3.5 用于定义协程的关键字,async定义一个协程,await用于挂起阻塞的异步调用接口,这两个关键字可以让代码看起来更简洁,表达力更强。
  6. run_until_complete(future),既可以接收 Future 对象,也可以是 coroutine 对象,如果是coroutine,则通过ensure_future()转化为future。
  7. asyncio.gather 可以将多个 Future 和 coroutine 封装成一个 Future,因为run_until_complete()只授受一个参数,所以当涉及多个协程调用时,gather()很有用。
  8. 可以通过loop.create_task(coroutine)创建task,也可以通过 asyncio.ensure_future(coroutine)创建task,两个方法的作用一样,但是create_task是3.4.2才有的,ensure_future()可以实用于以前的版本,但是ensure_future()在老版本的名字叫asyncio.async()。python3.7可以用asyncio.create_task()替换,这个方法比ensure_future更容易理解。看起来有点混乱,但任何东西发展都有一个过程,没办法。

协程第二版代码:

# -*- coding: UTF-8 -*-
#win7+python3.7
import asyncio
import itertools
import sys

async def spin(msg):  # <2>
    write, flush = sys.stdout.write, sys.stdout.flush
    for char in itertools.cycle('|/-\\'):
        status = char + ' ' + msg
        write(status)
        flush()
        write('\x08' * len(status))
        try:
            await asyncio.sleep(.1)  # <3>
        except asyncio.CancelledError:  # 下面的spinner.cancel()方法会抛出CancelledError异常
            break
    write(' ' * len(status) + '\x08' * len(status))

async def slow_function():  # <5>
    # pretend waiting a long time for I/O
    await asyncio.sleep(3)  # <6>
    return 42

async def supervisor():  # 监管员方法,因为调用协程方法的必须是协程或者loop,这个方法起一个程序流程的总控制作用
    spinner = asyncio.create_task(spin('thinking!'))  # 把spin协程包装成Task
    print('spinner object:', spinner)  # <9>
    result = await slow_function()  # <10>
    spinner.cancel()  # spinner任务被删除,抛出CancelledError异常
    return result

def main():
    loop = asyncio.get_event_loop()  # <12>
    result = loop.run_until_complete(supervisor())  # <13>
    loop.close()
    print('Answer:', result)

if __name__ == '__main__':
    main()

上面代码采用了新的关键字和函数,语义更加明确。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python中的线程协程都是用来实现并发的机制,但它们的实现方式有所不同。 Python线程的实现: Python线程是基于操作系统原生的线程实现的,即它们是由操作系统内核来调度和管理的。Python中的threading模块提供了线程的API,可以使用该模块来创建和管理线程线程的创建可以使用Thread类来实现,例如: ```python import threading def worker(): print('Worker') t = threading.Thread(target=worker) t.start() ``` 上述代码中,我们创建了一个名为worker()的函数,并将其作为线程的目标函数。我们使用Thread类创建了一个新的线程,并将worker函数作为其目标函数。最后,我们调用start()方法来启动线程Python协程的实现: Python协程是一种轻量级的并发机制,它可以在单个线程内实现多个任务的并发执行。Python协程的实现是基于生成器的,即协程是由生成器函数来实现的。Python中的asyncio模块提供了协程的API,可以使用该模块来创建和管理协程协程的创建可以使用async关键字和await关键字来实现,例如: ```python import asyncio async def worker(): print('Worker') asyncio.run(worker()) ``` 上述代码中,我们创建了一个名为worker()的协程函数,并使用async关键字来标识该函数是一个协程。我们使用asyncio模块的run()方法来运行该协程函数。协程函数中可以使用await关键字来等待其他协程或异步任务的完成。 总的来说,线程协程都是用来实现并发的机制,但线程是由操作系统内核来调度和管理的,而协程是由Python解释器来调度和管理的。线程适用于I/O密集型的任务,而协程适用于CPU密集型的任务。在Python中,协程的实现是基于生成器的,因此比线程更加轻量级和灵活。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值