同步v / s异步

时间:2015-06-26 18:20:08

标签: 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

异步

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)

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

1 个答案:

答案 0 :(得分:31)

异步调用的想法在许多与Web相关的编程中几乎相同... “stuff”(框架,服务器,库...... )不仅是Tornado Web服务器的概念。

基本理念是:

  • 在同步请求中,您发出请求并停止执行程序,直到您从HTTP服务器获得响应(如果无法访问服务器则出现错误,或者如果服务器正在取消,则出现超时)太长时间无法回复)解释器被阻止直到请求完成(直到你得到了对请求发生的事情的确切答案:它做得好吗?是否有错误?超时?... 。)。
  • 在异步请求中,您“启动”请求,并且您“忘掉它”,这意味着:解释器继续执行代码之后无需等待请求即可完成请求。

    这似乎......毫无意义,对吧?您将请求“发送到空白空间”,并继续照常执行?当服务器向您发送响应时会发生什么?我提出了要求,我想知道发生了什么事!否则,我不会在我的代码中键入,以开始!!

    嗯,这是callback进来的地方。你启动请求“到空白空间” 但是你提供了一个回调函数,所以当另一端的HTTP服务器向您发送响应,该函数以所述response作为第一个参数运行。

让我们看一下例子。

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

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

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()

打开终端并运行该代码以获得服务器。您将获得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()

这将输出:

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"

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

 ------ 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"

如果你看到,脚本asynchronous_fetch13: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

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

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

进一步推荐阅读: