【问题标题】:Asynchronous HTTP calls in PythonPython 中的异步 HTTP 调用
【发布时间】:2020-12-16 19:46:28
【问题描述】:

我需要 Python 中的回调类型的功能,我多次向 Web 服务发送请求,每次都更改参数。我希望这些请求同时发生而不是顺序发生,所以我希望函数被异步调用。

看起来 asyncore 是我可能想要使用的,但我所看到的关于它如何工作的示例看起来都有些矫枉过正,所以我想知道我是否应该走另一条路。关于模块/流程的任何建议?理想情况下,我想以程序方式使用这些而不是创建类,但我可能无法解决这个问题。

【问题讨论】:

  • 太过分了。我所需要的只是来自脚本中的同时 http 调用(我不需要从命令行调用进程等)。我只需要有回调功能,但我在 python 中找不到这个过程。进一步的研究将我引向 urllib2。
  • 矫枉过正?线程与从命令行调用进程无关。
  • tippytop,当然是用于传输的 urllib2.. 但您仍然需要并行生成它们。因此您可以进行线程处理、多处理、并发.futures 或基于异步 i/o 的解决方案。
  • @Falmarri 因为 python 线程很糟糕。

标签: python asynchronous asyncore


【解决方案1】:

从 Python 3.2 开始,您可以使用 concurrent.futures 来启动并行任务。

查看这个ThreadPoolExecutor 示例:

http://docs.python.org/dev/library/concurrent.futures.html#threadpoolexecutor-example

它产生线程来检索 HTML 并在收到响应时对其进行操作。

import concurrent.futures
import urllib.request

URLS = ['http://www.foxnews.com/',
        'http://www.cnn.com/',
        'http://europe.wsj.com/',
        'http://www.bbc.co.uk/',
        'http://some-made-up-domain.com/']

# Retrieve a single page and report the url and contents
def load_url(url, timeout):
    conn = urllib.request.urlopen(url, timeout=timeout)
    return conn.readall()

# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
    # Start the load operations and mark each future with its URL
    future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            data = future.result()
        except Exception as exc:
            print('%r generated an exception: %s' % (url, exc))
        else:
            print('%r page is %d bytes' % (url, len(data)))

上面的例子使用了线程。还有一个类似的ProcessPoolExecutor 使用进程池,而不是线程:

http://docs.python.org/dev/library/concurrent.futures.html#processpoolexecutor-example

import concurrent.futures
import urllib.request

URLS = ['http://www.foxnews.com/',
        'http://www.cnn.com/',
        'http://europe.wsj.com/',
        'http://www.bbc.co.uk/',
        'http://some-made-up-domain.com/']

# Retrieve a single page and report the url and contents
def load_url(url, timeout):
    conn = urllib.request.urlopen(url, timeout=timeout)
    return conn.readall()

# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
    # Start the load operations and mark each future with its URL
    future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            data = future.result()
        except Exception as exc:
            print('%r generated an exception: %s' % (url, exc))
        else:
            print('%r page is %d bytes' % (url, len(data)))

【讨论】:

    【解决方案2】:

    你知道eventlet吗?它允许您编写看似同步的代码,但让它在网络上异步运行。

    这是一个超极小爬虫的例子:

    urls = ["http://www.google.com/intl/en_ALL/images/logo.gif",
         "https://wiki.secondlife.com/w/images/secondlife.jpg",
         "http://us.i1.yimg.com/us.yimg.com/i/ww/beta/y3.gif"]
    
    import eventlet
    from eventlet.green import urllib2
    
    def fetch(url):
    
      return urllib2.urlopen(url).read()
    
    pool = eventlet.GreenPool()
    
    for body in pool.imap(fetch, urls):
      print "got body", len(body)
    

    【讨论】:

      【解决方案3】:

      Twisted framework 就是一张票。但是如果你不想这样做,你也可以使用 pycurl,libcurl 的包装器,它有自己的异步事件循环并支持回调。

      【讨论】:

      • 当我发布这篇文章时,我最终采用了 pycurl 方法(很抱歉迟到了接受)。
      • @tippytop 酷。您可能还对我在此之上的简化包装器感兴趣。 pycopia.WWW.client 模块。
      【解决方案4】:

      (虽然这个线程是关于服务器端 Python。因为这个问题是不久前被问到的。其他人可能会偶然发现这个问题,他们正在客户端寻找类似的答案)

      对于客户端解决方案,您可能需要查看 Async.js 库,尤其是“控制流”部分。

      https://github.com/caolan/async#control-flow

      通过将“平行”与“瀑布”相结合,您可以获得您想要的结果。

      WaterFall( Parallel(TaskA, TaskB, TaskC) -> PostParallelTask​​)

      如果您检查 Control-Flow - “Auto” 下的示例,他们会为您提供上述示例: https://github.com/caolan/async#autotasks-callback 其中“write-file”取决于“get_data”和“make_folder”,“email_link”取决于 write-file”。

      请注意,所有这些都发生在客户端(除非您正在使用 Node.JS - 在服务器端)

      对于服务器端 Python,请查看 PyCURL @https://github.com/pycurl/pycurl/blob/master/examples/basicfirst.py

      下面的例子结合pyCurl,可以实现非阻塞多线程的功能。

      【讨论】:

      • 这不是一个 thread - 这是一个问题。这似乎没有回答它......
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-03
      • 2021-12-25
      • 2021-08-23
      • 2018-05-21
      相关资源
      最近更新 更多