如何在Python3中检测concurrent.futures中的异常?

时间:2015-10-31 05:17:47

标签: python python-2.7 multiprocessing python-3.4 concurrent.futures

由于其并发期货模块,我刚刚转到python3。我想知道我是否可以让它来检测错误。我想将并发期货用于并行程序,如果有更高效的模块请告诉我。

我不喜欢多处理,因为它太复杂而且没有太多的文档。然而,如果有人可以编写一个没有类的Hello World,那么将使用多处理来并行计算,这样很容易理解。

这是一个简单的脚本:

from concurrent.futures import ThreadPoolExecutor

def pri():
    print("Hello World!!!")

def start():
    try:
        while True:
            pri()
    except KeyBoardInterrupt:
        print("YOU PRESSED CTRL+C")


with ThreadPoolExecutor(max_workers=3) as exe:
    exe.submit(start)

上面的代码只是一个演示,说明CTRL + C无法打印声明。

我想要的是能够调用函数是否存在错误。此错误检测必须来自函数本身。

另一个例子

import socket
from concurrent.futures import ThreadPoolExecutor 
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
def con():
    try:
        s.connect((x,y))
        main()
    except: socket.gaierror
         err()
def err():
    time.sleep(1)
    con()
def main():
    s.send("[+] Hello")
with ThreadPoolExecutor as exe:
    exe.submit(con)

2 个答案:

答案 0 :(得分:3)

Here是一个解决方案。我不确定你喜欢它,但我想不出任何其他的。我已修改您的代码以使其正常工作。

from concurrent.futures import ThreadPoolExecutor
import time

quit = False

def pri():
    print("Hello World!!!")

def start():
    while quit is not True:
        time.sleep(1)
        pri()

try:
    pool = ThreadPoolExecutor(max_workers=3)
    pool.submit(start)

    while quit is not True:
        print("hei")
        time.sleep(1)
except KeyboardInterrupt:
    quit = True

以下是要点:

  1. 使用with ThreadPoolExecutor(max_workers=3) as exe时,它会等待所有任务完成。看看Doc

      

    如果wait为True,则此方法将不会返回,直到所有待处理的期货都执行完毕并且与执行程序关联的资源已被释放。如果等待为False,则此方法将立即返回,并且当执行所有待处理的期货时,将释放与执行程序关联的资源。无论wait的值如何,整个Python程序都不会退出,直到所有待处理的期货都执行完毕。

         

    如果使用with语句,则可以避免必须显式调用此方法,这将关闭Executor(等待Executor.shutdown()被调用,等待设置为{{1 }})

    就像在线程上调用True一样 这就是为什么我用它替换它:

    join()
  2. 主线程必须“工作”才能捕获Ctrl + C.所以你不能只是将主线程留在那里并退出,最简单的方法是运行无限循环

  3. 现在您已经在主线程中运行了循环,当您点击pool = ThreadPoolExecutor(max_workers=3) pool.submit(start) 时,程序将进入CTRL+C块并设置except KeyboardInterrupt。然后您的工作线程可以退出。

  4. 严格来说,这只是一种解决方法。在我看来,这是不可能有另一种方式。

    修改
    我不确定是什么困扰你,但你可以在另一个线程中捕获异常而没有问题:

    quit=True

    输出

    import socket
    import time
    from concurrent.futures import ThreadPoolExecutor 
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    
    def con():
        try:
            raise socket.gaierror
            main()
        except socket.gaierror:
            print("gaierror occurred")
            err()
    
    def err():
        print("err invoked")
        time.sleep(1)
        con()
    
    def main():
        s.send("[+] Hello")
    
    with ThreadPoolExecutor(3) as exe:
        exe.submit(con)
    

答案 1 :(得分:0)

参加聚会的方式为时已晚,但也许会对其他人有所帮助...

我很确定原来的问题没有得到真正回答。人们感到不安的是,当用户5327424使用键盘中断来引发异常时,关键是未引发异常(无论如何引起)。例如:

import concurrent.futures


def main():
    numbers = range(10)

    with concurrent.futures.ThreadPoolExecutor() as executor:
        results = {executor.submit(raise_my_exception, number): number for number in numbers}


def raise_my_exception(number):
    print('Proof that this function is getting called. %s' % number)
    raise Exception('This never sees the light of day...')


main()

执行上面的示例代码时,您将在屏幕上看到显示在打印语句中的文本,但是您将永远不会看到异常。这是因为每个线程的结果都保存在results对象中。您需要迭代该对象以获取异常。以下示例显示了如何访问结果。

import concurrent.futures


def main():
    numbers = range(10)

    with concurrent.futures.ThreadPoolExecutor() as executor:
        results = {executor.submit(raise_my_exception, number): number for number in numbers}

    for result in results:
        # This will cause the exception to be raised (but only the first one)
        print(result.result())


def raise_my_exception(number):
    print('Proof that this function is getting called. %s' % number)
    raise Exception('This will be raised once the results are iterated.')


main()

我不确定我是否喜欢这种行为,但是它确实允许线程完全执行,而不管各个线程内部遇到什么异常。