18

I have just moved on to python3 as a result of its concurrent futures module. I was wondering if I could get it to detect errors. I want to use concurrent futures to parallel program, if there are more efficient modules please let me know.

I do not like multiprocessing as it is too complicated and not much documentation is out. It would be great however if someone could write a Hello World without classes only functions using multiprocessing to parallel compute so that it is easy to understand.

Here is a simple script:

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)

The above code was just a demo, of how CTRL+C will not work to print the statement.

What I want is to be able to call a function is an error is present. This error detection must be from the function itself.

Another example

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)
Stidgeon
  • 2,673
  • 8
  • 20
  • 28

2 Answers2

20

Way too late to the party, but maybe it'll help someone else...

I'm pretty sure the original question was not really answered. Folks got hung up on the fact that user5327424 was using a keyboard interrupt to raise an exception when the point was that the exception (however it was caused) was not raised. For example:

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

When the example code above is executed, you will see the text inside the print statement displayed on the screen, but you will never see the exception. This is because the results of each thread are held in the results object. You need to iterate that object to get to your exceptions. The following example shows how to access the 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()

I'm not sure I like this behavior or not, but it does allow the threads to fully execute, regardless of the exceptions encountered inside the individual threads.

Hans Goldman
  • 564
  • 3
  • 12
4

Here's a solution. I'm not sure you like it, but I can't think of any other. I've modified your code to make it work.

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

Here are the points:

  1. When you use with ThreadPoolExecutor(max_workers=3) as exe, it waits until all tasks have been done. Have a look at Doc

    If wait is True then this method will not return until all the pending futures are done executing and the resources associated with the executor have been freed. If wait is False then this method will return immediately and the resources associated with the executor will be freed when all pending futures are done executing. Regardless of the value of wait, the entire Python program will not exit until all pending futures are done executing.

    You can avoid having to call this method explicitly if you use the with statement, which will shutdown the Executor (waiting as if Executor.shutdown() were called with wait set to True)

    It's like calling join() on a thread.
    That's why I replaced it with:

    pool = ThreadPoolExecutor(max_workers=3)
    pool.submit(start)
    
  2. Main thread must be doing "work" to be able to catch a Ctrl+C. So you can't just leave main thread there and exit, the simplest way is to run an infinite loop

  3. Now that you have a loop running in main thread, when you hit CTRL+C, program will enter the except KeyboardInterrupt block and set quit=True. Then your worker thread can exit.

Strictly speaking, this is only a workaround. It seems to me it's impossible to have another way for this.

Edit
I'm not sure what's bothering you, but you can catch exception in another thread without problem:

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)

Output

gaierror occurred
err invoked
gaierror occurred
err invoked
gaierror occurred
err invoked
gaierror occurred
...
Community
  • 1
  • 1
laike9m
  • 18,344
  • 20
  • 107
  • 140
  • Nah unfortunately, this is not what i neede. I need to catch exceptions from the function itself. But this deserves an upvote. Could python2.7 solve my problem? –  Nov 01 '15 at 06:27
  • "catch exceptions" != "catch ctrl+c". If you want to catch keyboard interrupt, I'm afraid this is the only way. – laike9m Nov 01 '15 at 07:34
  • @IsithaSubasinghe Then just catch it. – laike9m Nov 01 '15 at 08:29
  • I want to catch it so that it can it can try again so con() try: s.connect((x,y)) with except: main() . def main(): print "error", time.sleep(1), con()..............Sorry about the bad formatting, I'll make a new question if you want me to –  Nov 01 '15 at 09:45
  • There you go made it better –  Nov 01 '15 at 09:54
  • Doesnt work for me, it doesnt actually connect and get to main() –  Nov 04 '15 at 01:45
  • @IsithaSubasinghe What output did you see? What Python version are you using? On what platform? – laike9m Nov 04 '15 at 02:01
  • @IsithaSubasinghe I see. I didn't write code that you can actually use, just to prove my point. I raise an exception before `main`, of course you can't get to `main`. – laike9m Nov 04 '15 at 02:03
  • yeah i know i removed the raise and tried connecting to an open port on my laptop but it didn't actually work –  Nov 04 '15 at 02:23
  • It just skips the connect((x,y)) has the same output. –  Nov 04 '15 at 02:29
  • @IsithaSubasinghe If you do want to get your code to work, you really should raise another question. I think this question is only about how to detect exception. If you try to solve multiple problems here, it will confuse future readers. – laike9m Nov 04 '15 at 02:30
  • Here is my real problem http://stackoverflow.com/questions/33513017/parallel-compute-task-to-brute-force-in-python I posted the above so that other people could benefit from it as python parallelism is a pain –  Nov 04 '15 at 03:07
  • I'm so sorry for the above post, thankyou for you help, I made a simple stupid mistake, once again I apoligize about this whole question. –  Nov 04 '15 at 03:47
  • @IsithaSubasinghe There's no stupid question, you really don't need to apologize. – laike9m Nov 04 '15 at 06:47