Skip to content

Latest commit

 

History

History
101 lines (71 loc) · 3.96 KB

28.协程-常见问题.md

File metadata and controls

101 lines (71 loc) · 3.96 KB

常见问题

一.很多个协程一起运行有创建新的线程吗?

协程运行时,都是在一个线程中运行的,没有创建新的线程。如下

import asyncio
import time
import threading
 
a=time.time()
 
async def hello1():
    print(f"Hello world 01 begin,my thread is:{threading.currentThread()}")
    await asyncio.sleep(3)
    print("Hello again 01 end")
 
async def hello2():
    print(f"Hello world 02 begin,my thread is:{threading.currentThread()}")
    await asyncio.sleep(2)
    print("Hello again 02 end")
 
async def hello3():
    print(f"Hello world 03 begin,my thread is:{threading.currentThread()}")
    await asyncio.sleep(1)
    print("Hello again 03 end")
 
loop = asyncio.get_event_loop()
tasks = [hello1(), hello2(),hello3()]
loop.run_until_complete(asyncio.wait(tasks))
 
loop.close()
 
 
b=time.time()
print('---------------------------------------')
print(b-a)

从上面那个可以看出,三个不同的协程函数都是在一个线程完成的。但是并不是意味着,多个协程函数只能在一个线程中执行,同样可以创建新的线程,其实我们完全可以在新的线程中重新创建一个事件循环,具体的实例参见后面。

二.线程一定效率更高吗?

也不是绝对的,当然在一般情况下,异步方式的执行效率是更高的,就比如上面的三个函数,如果按照同步的方式执行,则一共需要6秒的时间,但是采用协程则只需要最长的那个时间3秒,这自然是提高了工作效率,那是不是一定会提高呢?也不一定,这与协程的调用方式是由密切关系的。如下所示:

import asyncio
import time
import threading
 
a=time.time()
 
async def hello1():
    print(f"Hello world 01 begin,my thread is:{threading.currentThread()}")
    await asyncio.sleep(3)
    print("Hello again 01 end")
 
async def hello2():
    print(f"Hello world 02 begin,my thread is:{threading.currentThread()}")
    await asyncio.sleep(2)
    print("Hello again 02 end")
 
async def hello3():
    print(f"Hello world 03 begin,my thread is:{threading.currentThread()}")
    await hello2()
    await hello1()
    print("Hello again 03 end")
 
loop = asyncio.get_event_loop()
tasks = [hello3()]
loop.run_until_complete(asyncio.wait(tasks))
 
loop.close()
 
b=time.time()
print('---------------------------------------')
print(b-a)

我们发现一个问题,上面执行的顺序完全不是异步执行,执行的时间也没有得到改善,究其原因,是因为上面是通过hello3去调用hello1和hello2的,这和同步调用的方式完全是一样的,即使我定义的都是异步方法,它既没有提高执行效率,还会有阻塞。

结论:

在有很多个异步方式的时候,一定要尽量避免这种异步函数的直接调用,这和同步是没什么区别的,一定要通过事件循环loop,“让事件循环在各个异步函数之间不停游走”,这样才不会造成阻塞。

三.协程会不会有阻塞呢?

异步方式依然会有阻塞的,当我们定义的很多个异步方法彼此之间有一来的时候,比如,我必须要等到函数1执行完毕,函数2需要用到函数1的返回值,如上面的例子2所示,就会造成阻塞,这也是异步编程的难点之一,如何合理配置这些资源,尽量减少函数之间的明确依赖,这是很重要的。

四.协程的4种状态

协程函数相比于一般的函数来说,我们可以将协程包装成任务Task,任务Task就在于可以跟踪它的状态,我就知道它具体执行到哪一步了,一般来说,协程函数具有4种状态,可以通过相关的模块进行查看,请参见前面的文章,

他的四种状态为:

Pending Running Done Cacelled 创建future的时候,task为pending,事件循环调用执行的时候当然就是running,调用完毕自然就是done,如果需要停止事件循环,中途需要取消,就需要先把task取消,即为cancelled。