同步v/s异步

phr*_*iac 12 python asynchronous callback tornado synchronous

我想了解龙卷风文档介绍页面上提供的基本示例.它有2个代码块.同步一个对我来说很好,我也理解它.但异步的是我无法理解的.

同步

from tornado.httpclient import HTTPClient

def synchronous_fetch(url):
    http_client = HTTPClient()
    response = http_client.fetch(url)
    return response.body
Run Code Online (Sandbox Code Playgroud)

异步

from tornado.httpclient import AsyncHTTPClient

def asynchronous_fetch(url, callback):
    http_client = AsyncHTTPClient()
    def handle_response(response):
        callback(response.body)
    http_client.fetch(url, callback=handle_response)
Run Code Online (Sandbox Code Playgroud)

如果您能提供更好的示例,请执行此操作.

Bor*_*jaX 34

在许多与Web相关的编程中,异步调用的思想几乎相同...... "东西"(框架,服务器,库......)不仅是Tornado Web服务器的概念.

基本思路是:

  • 在同步请求中,您发出请求并停止执行程序,直到您从HTTP服务器获得响应(或者如果无法访问服务器则出现错误,或者如果服务器正在取消,则会超时)回复)解释器被阻止,直到请求完成(直到你得到关于请求发生的事情的确切答案:它是否顺利?是否有错误?超时?...).
  • 在异步请求中,您"启动"请求,并且有点"忘记它",这意味着:解释器在请求发出后继续执行代码,而不等待请求完成.

    这似乎......毫无意义,对吧?你发送请求"空间无效",并继续像往常一样执行?当服务器向您发送响应时会发生什么?我提出了要求,我想知道发生了什么事!否则,我不会在我的代码中键入它开始!!

    好吧,这就是它的callback用武之地.你启动了"空间空白" 的请求但是你提供了一个回调函数,所以当另一端的HTTP服务器向你发送它的响应时,该函数以所述response的第一个参数运行.

让我们看一下en例子吧.

我创建了一个非常简单的Tornado服务器(使用Python 2.7Tornado 4.2)只有一个处理程序.在a上GET,返回需要5秒钟.我已经用time.sleep做到了,但在现实生活中,这可能是一个非常耗时的过程(访问数据库,执行一些计算......谁知道?...)

这是服务器文件(基于Tornado文档中提供的示例):

SampleServer.py:

#!/usr/bin/env python2.7
import time
import tornado.ioloop
import tornado.web


class MainHandler(tornado.web.RequestHandler):
    def get(self):
        print "Someone is GET'ing me"
        time.sleep(5)
        self.write("Hello, world")

application = tornado.web.Application([
        (r"/", MainHandler),
    ])

if __name__ == "__main__":
    application.listen(8888)
    print "Starting sample server."
    tornado.ioloop.IOLoop.current().start()
Run Code Online (Sandbox Code Playgroud)

打开终端并运行该代码以获得服务器.你会得到一个Tornado监听8888本地机器的端口.

现在,让我们创建另一个脚本(你必须在另一个终端上运行),其GETš http://localhost:8888在两个方面:一是同步,然后异步.

SampleFetcher.py:

#!/usr/bin/env python2.7
import datetime
import tornado.ioloop
from tornado.httpclient import HTTPClient, AsyncHTTPClient


def HUMAN_DT_NOW():
    return datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")


def synchronous_fetch(url):
    http_client = HTTPClient()
    start_dt = datetime.datetime.now()
    response = http_client.fetch(url)
    end_dt = datetime.datetime.now()
    print ("The synchronous fetch took %s seconds."
           % (end_dt - start_dt).total_seconds())
    print "(Sync) Server said: \"%s\"" % response.body


def asynchronous_fetch(url):
    http_client = AsyncHTTPClient()

    def handle_response(response):
        print ""
        print "Yawwza... Finally!!!."
        print "The time now is %s" % HUMAN_DT_NOW()
        print "(Async) Server said: \"%s\"" % response.body
    print "Gonna launch a 'fetch' to the universe at %s..." % HUMAN_DT_NOW()
    http_client.fetch(url, callback=handle_response)

if __name__ == "__main__":
    print " ------ Synchronous ------ "
    print ("Starting synchronous fetch at %s."
           " The program will block for about 5 secs." % HUMAN_DT_NOW())
    synchronous_fetch('http://localhost:8888')
    print "Pfew! That was a lot of wait time!!. I got bored watching my terminal"
    print ""
    print "Aight, let's see what Asynchronous can do"
    print " ------ Asynchronous ------ "
    asynchronous_fetch('http://localhost:8888')
    print "You're gonna see this line before the \"Yawwza...\" one"
    print "This one too. Now is %s" % HUMAN_DT_NOW()
    # The IOLoop below is required to prevent the script from closing ahead
    # of time, but allowing Asynchronous interactions
    tornado.ioloop.IOLoop.current().start()
Run Code Online (Sandbox Code Playgroud)

这将输出:

Starting synchronous fetch at 2015/07/04 13:25:47. The program will block for about 5 secs.
The synchronous fetch took 5.009597 seconds.
(Sync) Server said: "Hello, world"
Pfew! That was a lot of wait time!!. I got bored watching my terminal

Aight, let's see what Asynchronous can do
 ------ Asynchronous ------ 
Gonna launch a 'fetch' to the universe at 2015/07/04 13:25:52...
You're gonna see this line before the "Yawwza..." one
This one too. Now is 2015/07/04 13:25:52

Yawwza... Finally!!!.
The time now is 2015/07/04 13:25:57
(Async) Server said: "Hello, world"
Run Code Online (Sandbox Code Playgroud)

让我们关注异步部分,这里:

 ------ Asynchronous ------ 
Gonna launch a 'fetch' to the universe at 2015/07/04 13:25:52...
You're gonna see this line before the "Yawwza..." one
This one too. Now is 2015/07/04 13:25:52

Yawwza... Finally!!!.
The time now is 2015/07/04 13:25:57
(Async) Server said: "Hello, world"
Run Code Online (Sandbox Code Playgroud)

如果你看到,脚本发出了asynchronous_fetchat 13:25:52,但是立即(在同一秒内),解释器继续执行,并在发出请求后运行下一个语句(打印的行You're gonna see this line before the "Yawwza..." oneThis one too. Now is 2015/07/04 13:25:52).

然后,大约5秒钟后,服务器响应,并执行了callback功能(当时handle_response),就在你看到的时候

Yawwza... Finally!!!.
The time now is 2015/07/04 13:25:57
Run Code Online (Sandbox Code Playgroud)

我希望这有助于理解这个想法.这是一个非常有用的概念,它不仅适用于龙卷风.

随意使用提供的两个示例脚本,更改内容,增加服务器回复的时间...

进一步推荐阅读:

  • 好的帖子和例子。Tnx。 (2认同)