为什么在concurrent.futures.Future实例中没有引发TimeoutError

时间:2015-01-23 01:13:02

标签: python python-3.x concurrency

我基于https://docs.python.org/3/library/concurrent.futures.html#id1的样本。

我更新了以下内容:
data = future.result()
对此:
data = future.result(timeout=0.1)

concurrent.futures.Future.result州的文档:

  

如果调用未在超时秒内完成,则会引发TimeoutError。 timeout可以是int或float

(我知道请求超时60,但在我的真实代码中,我执行了不使用urllib请求的其他操作) < / p>

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:
            # The below timeout isn't raising the TimeoutError.
            data = future.result(timeout=0.01)
        except Exception as exc:
            print('%r generated an exception: %s' % (url, exc))
        else:
            print('%r page is %d bytes' % (url, len(data)))
如果我在调用TimeoutError时设置了

as_completed,但是我需要在每个Future的基础上设置超时,而不是将它们全部设置为整体。


更新

谢谢@jme,它适用于单个Future,但不能使用下面的倍数。我是否需要在函数开头yield允许futures dict的构建?从文档中可以看出,submit的调用不应该阻止。

import concurrent.futures
import time
import sys

def wait():
    time.sleep(5)
    return 42

with concurrent.futures.ThreadPoolExecutor(4) as executor:
    waits = [wait, wait]
    futures = {executor.submit(w): w for w in waits}
    for future in concurrent.futures.as_completed(futures):
        try:
            future.result(timeout=1)
        except concurrent.futures.TimeoutError:
            print("Too long!")
            sys.stdout.flush()

print(future.result())

2 个答案:

答案 0 :(得分:1)

在主线程中引发了 异常,你只是没有看到它,因为stdout没有被刷新。试试例如:

import concurrent.futures
import time
import sys

def wait():
    time.sleep(5)
    return 42

with concurrent.futures.ThreadPoolExecutor(4) as executor:
    future = executor.submit(wait)
    try:
        future.result(timeout=1)
    except concurrent.futures.TimeoutError:
        print("Too long!")
        sys.stdout.flush()

print(future.result())

运行这个,你会看到太长时间!&#34;在一秒钟后出现,但是解释器将再等待四秒钟以使线程完成执行。然后,您会看到42 - wait()的结果 - 出现。

这是什么意思?设置超时并不会杀死线程,这实际上是一件好事。如果线程正在锁定怎么办?如果我们突然杀了它,那个锁永远不会被释放。不,让线程处理自己的死亡要好得多。同样,future.cancel的目的是阻止线程启动,而不是杀死它。

答案 1 :(得分:1)

问题似乎是对concurrent.futures.as_completed()的调用。

如果我用for循环替换它,一切似乎都有效:

for wait, future in [(w, executor.submit(w)) for w in waits]:
    ...

我误解了as_completed的文档:

  

...在完成(已完成或被取消)时产生期货......

as_completed将处理超时但总体而言,不会在将来的基础上进行。