python处理流程-在python异步协程中处理流程分析(一)

之前的一篇文章python中的asyncio使用详解介绍了在python3 中的asyncio的基础使用,可以在实际的工作中,由于以前写了太多的多线程与多进程,所以对于以前编写风格和一些由于没有异步支持的库函数来说,由于要写在异步里,所以对于编写代码来说还是要处理很多同步的方法,今天在这里整理一下在异步操作中如果处理同步的函数问题。

为了更好的演示,我准备了三个函数,一个同步的函数,两个异步的函数

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21# 定义阻塞的函数

def ping(url):

print("阻塞函数开始运行")

time.sleep(2)

os.system("ping %s"%url)

print("阻塞函数运行结束")

# 定义两个异步函数

async def asyncfunc1():

print("Suspending func1")

await asyncio.sleep(1)

print("func func1 ", threading.current_thread())

print('Resuming func1')

return "func1"

async def asyncfunc2():

print("Suspending func2")

await asyncio.sleep(1)

print("func func2 ", threading.current_thread())

print('Resuming func2')

return "func2"

协程中控制任务

单个协程任务的运行

上面的函数,比如说我只想将asyncfunc1() 函数运行并且得结果,可以使用loop.create_task()方法创建一个task对象,task是Futures的子类,当调用loop.run_until_complete() 以后,协程跑完以后,通过task.result()获取协程函数的返回结果。

1

2

3

4

5

6

7

8

9

10

11

12

13async def asyncfunc1():

print("Suspending func1")

await asyncio.sleep(1)

print("func func1 ", threading.current_thread())

print('Resuming func1')

return "func1"

if __name__=="__main__":

print("In main thread ",threading.current_thread())

loop = asyncio.get_event_loop()

task = loop.create_task(asyncfunc1())

loop.run_until_complete(task)

print("task result is ",task.result())

输出结果为

1

2

3

4

5In main thread <_MainThread(MainThread, started 6140)>

Suspending func1

func func1 <_MainThread(MainThread, started 6140)>

Resuming func1

task result is func1

主线程和跑的协程函数是在同一个线程中。

也可以给task对象添加一个回调方法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23#coding:gbk

import asyncio

import time,sys

async def asyncfunc1():

print("Suspending func1")

await asyncio.sleep(1)

print("func func1 ", threading.current_thread())

print('Resuming func1')

return "func1"

# 定义一个回调函数

def callbackfunc(task):

print("task 运行结束,它的结果是:",task.result())

if __name__=="__main__":

print("In main thread ",threading.current_thread())

loop = asyncio.get_event_loop()

task = loop.create_task(asyncfunc1())

task.add_done_callback(callbackfunc)

loop.run_until_complete(task)

输出结果为

1

2

3

4

5In main thread <_MainThread(MainThread, started 11248)>

Suspending func1

func func1 <_MainThread(MainThread, started 11248)>

Resuming func1

task 运行结束,它的结果是: func1

loop.run_until_complete 是一个阻塞方法,只有当它里面的协程运行结束以后这个方法才结束,才会运行之后的代码。

其实也可以不调用loop.run_until_complete方法,创建一个task以后,其实就已经在跑协程函数了,只不过当事件循环如果准备开始运行了,此时的task状态是pending,如果不调用事件循环的话,则不会运行协程函数,由于主线程跑完了,子线程也就被销毁了,如代码写成这样:

1

2

3

4

5if __name__=="__main__":

print("In main thread ",threading.current_thread())

loop = asyncio.get_event_loop()

task = loop.create_task(asyncfunc1())

time.sleep(3)

得到的输出是

1

2

3

4In main thread <_MainThread(MainThread, started 6056)>

Task was destroyed but it is pending!

task: cb=[callbackfunc() at test.py:39]>

sys:1: RuntimeWarning: coroutine 'asyncfunc1' was never awaited

所以想要使得协程函数得到执行,需要调用事件循环来执行任务,上面的loop.run_until_complete就是使循环开始跑了,其实也可以使用loop.run_forever(),这个函数就像它的名字一样,会一直跑。只有事件循环跑起来了,那么使用该循环注册的协程才会得到执行,但是如果使用loop.run_forever()则会阻塞在这里,事件循环还有一个stop方法,可以结束循环,我们可以在task对象上添加一个回调方法,当协程执行结束以后,调用事件循环的stop方法来结束整个循环

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23#coding:gbk

import asyncio

import time,sys

async def asyncfunc1():

print("Suspending func1")

await asyncio.sleep(1)

print("func func1 ", threading.current_thread())

print('Resuming func1')

return "func1"

# 定义一个回调函数

def callbackfunc(task):

print("task 运行结束,它的结果是:",task.result())

loop.stop()

if __name__=="__main__":

print("In main thread ",threading.current_thread())

loop = asyncio.get_event_loop()

task = loop.create_task(asyncfunc1())

task.add_done_callback(callbackfunc)

loop.run_forever()

除了使用loop.run_until_complete方法,还可以使用asyncio.ensure_future() 方法来运行协程,将上面代码中的task = loop.create_task(asyncfunc1()) 改为 task = asyncio.ensure_future(asyncfunc1())会得到相同的结果,它的参数是协程对象或者futures,也可以传task对象,因为task是futures的子类,当传入的是一个协程对象时,返回一个task对象,传入一个futures的时候,直接返回futures对象,也就是说,在调用asyncio.ensure_future()以后,都会返回一个task对象,都可以为它添加一个回调方法,并且可以调用task.result()方法得到结果(注意如果task没有执行结束就调用result方法,则会抛异常)。

多个协程任务的并行

最上面我准备了两个异步的函数asyncfunc1和asyncfunc2,如果我想要这两个函数同时执行,并且得到它们的返回值该怎么操作呢?

有了上面单协程的经验,我们也可以使用事件循环创建两个task,然后在run_forever()来执行,可以对task添加回调,将结果输出。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32#coding:gbk

import asyncio

# 定义两个异步函数

async def asyncfunc1():

print("Suspending func1")

await asyncio.sleep(1)

print("func func1 ", threading.current_thread())

print('Resuming func1')

return "func1"

async def asyncfunc2():

print("Suspending func2")

await asyncio.sleep(1)

print("func func2 ", threading.current_thread())

print('Resuming func2')

return "func2"

# 定义一个回调函数

def callbackfunc(task):

print("task 运行结束,它的结果是:",task.result())

if __name__=="__main__":

print("In main thread ",threading.current_thread())

loop = asyncio.get_event_loop()

task1 = loop.create_task(asyncfunc1())

task1.add_done_callback(callbackfunc)

task2 = loop.create_task(asyncfunc2())

task2.add_done_callback(callbackfunc)

loop.run_forever()

输出结果是

1

2

3

4

5

6

7

8

9In main thread <_MainThread(MainThread, started 8040)>

Suspending func1

Suspending func2

func func1 <_MainThread(MainThread, started 8040)>

Resuming func1

func func2 <_MainThread(MainThread, started 8040)>

Resuming func2

task 运行结束,它的结果是: func1

task 运行结束,它的结果是: func2

此时由于loop调用了run_forever方法,且没有方法调用stop方法,所以程序会一直卡着。

这样是可以将多个协程跑起来,但这样的处理一是繁琐,二是不方便结果的回收。

asyncio有一个gather方法,可以传入多个任务对象,当调用await asyncio.gather(*) 时,它会将结果全部返回

由于await 只能写在async def 函数中,所以这里还需要新创建一个函数

1

2

3

4

5

6

7

8

9

10

11async def main():

task1 = loop.create_task(asyncfunc1())

task1.add_done_callback(callbackfunc)

task2 = loop.create_task(asyncfunc2())

task2.add_done_callback(callbackfunc)

result = await asyncio.gather(task1,task2)

print(result)

async def mian2():

result = await asyncio.gather(asyncfunc1(),asyncfunc2())

print(result)

两种定义方式都可以,一个是向gather函数传的是协程对象,一个是传的task对象。之后在调用

1

2

3

4if __name__=="__main__":

print("In main thread ",threading.current_thread())

loop = asyncio.get_event_loop()

loop.run_until_complete(main()) # or main2()

得到的输出为

1

2

3

4

5

6

7

8

9

10In main thread <_MainThread(MainThread, started 7016)>

Suspending func1

Suspending func2

func func1 <_MainThread(MainThread, started 7016)>

Resuming func1

func func2 <_MainThread(MainThread, started 7016)>

Resuming func2

task 运行结束,它的结果是: func1

task 运行结束,它的结果是: func2

['func1', 'func2']

这样就达到的协程的并行与结果的回收。

这篇文章先简单介绍到这里,之后会继续分析同步代码的执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值