23

在Python中实现异步编程,只需要这几步就够了

 3 years ago
source link: http://news.51cto.com/art/202010/629618.htm
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

EZzEF3Y.jpg!mobile

图源:unsplash

异步编程是并行编程的一种方式。单个工作单元独立于主应用程序线程运行,并通知调用线程其完成、失败情况或进度。下面这张图理解起来会更直观一些:

ZFZVNrI.jpg!mobile

同步vs异步

同步编程很普遍。如图,请求1被发出后等待响应1;一旦得到响应1就发出请求2,然后等待它的响应。在上面的代码中,向函数传递参数“a”后等待函数返回更改后的值,然后再次调用以更改数字,最后再次得到响应,这就是同步编程。

而对于异步编程来说,请求1被发出后,无需等响应1便可直接发出请求2。两个请求完成后得到两个响应。简单地说就是请求1和请求2是并行处理的,不等前一个请求的响应便提出新的请求。

简言之,只要打开任务管理器(macOS中的活动监视器)就能看到多个应用程序同步运行;或者一个Python Shell在两个不同的终端窗口中运行。专业术语叫做多进程(MultiProcessing),顾名思义,即不止一个进程在运行。

如何在Python中进行异步编程?

一个同步编程的示例代码如下:

deffun(length,a): 
                  b = a 
                  for i inrange(length): 
                      a+=1 
                  print("value of a before: "+str(b)+" now it's "+str(a)) 
                  return a 
                  
              defmain(): 
                  r1 =fun(50000000,0) 
                  r2 =fun(100,12) 
                  r3 =fun(100,41) 
              if __name__=="__main__": 
                  main() 

以上代码的输出:

jaUfAr7.jpg!mobile

这段代码传递了for循环的范围。执行代码耗时长达13.843秒,因为r1的范围是5000,所以耗时久。现在的问题是,必须先待r1任务完成,否则无法得到r2和r3。可能在得到r1之前就得到r2和r3吗?答案是肯定的,这正是异步编程的用武之地。

首先用pip指令安装异步包。

pip install asyncio 

安装后,看一下新代码。使用异步包:

import asyncio 
           asyncdeffun(length,a): 
           b = a 
           for i inrange(length): 
               a+=1 
               if i %10000==0: 
                   await asyncio.sleep(0.0001) 
               print("value of a before: "+str(b)+" now it's "+str(a)) 
           return a 
           asyncdefmain(): 
           #creating subroutines. 
           t1 = loop.create_task(fun(50000000,0)) 
           t2 = loop.create_task(fun(100,12)) 
           t3 = loop.create_task(fun(100,41)) 
               await asyncio.wait([t1,t2,t3]) 
           if __name__=="__main__": 
           loop = asyncio.get_event_loop() 
           loop.run_until_complete(main()) 
           loop.close() 

首先观察该代码的输出,接下来讨论该代码:

muUNziE.jpg!mobile

输出-1

MVvU3mJ.jpg!mobile

输出-2

输出-1中首先能得到t2和t3进程的结果,然后在输出-2的截图中得到了t1进程的结果,这是异步编程的功劳。t1进程耗时最长,所以它的结果最后产生,且t1、t2和t3进程均并行运行。异步编程的好处就在于不必等待任何进程的结果,便可获得下一个进程的结果。

让我们讨论一下此代码。

首先,在if __name__=="__main__"中定义了asyncio.get_event_loop(),并将这个循环作为处理循环事件的异步对象。然后创建一个main的例行程序,并设置条件:若main没完成则继续循环。每次异步,都要进行loop.close()的编程,否则结果就会错误或异常。

然后将函数定义为asyncdeffunc_name,这样解释器就知道函数用了异步的方法。在main()中定义了三个任务(也可称为子例程),并使用了await函数,以便它等待三个进程结束(即使它没有多大意义,也必须使用它)。

最后用了fun()函数。i %10000的if条件让最大范围的进程徐徐运行,最后得到了答案。仔细研究fun()函数并自己尝试的话,其中的逻辑会显得非常合理和直接。

在Python中实现异步编程,你学会了吗?


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK