Python: concurrent.futures How to make it cancelable?

后端 未结 3 1960
-上瘾入骨i
-上瘾入骨i 2020-12-03 13:50

Python concurrent.futures and ProcessPoolExecutor provide a neat interface to schedule and monitor tasks. Futures even provide a .cancel() method:

3条回答
  •  天命终不由人
    2020-12-03 14:38

    I found your question interesting so here's my finding.

    I found the behaviour of .cancel() method is as stated in python documentation. As for your running concurrent functions, unfortunately they could not be cancelled even after they were told to do so. If my finding is correct, then I reason that Python does require a more effective .cancel() method.

    Run the code below to check my finding.

    from concurrent.futures import ProcessPoolExecutor, as_completed
    from time import time 
    
    # function that profits from partitioned search space
    def m_run(partition):
        for elem in partition:
            if elem == 3351355150:
                return elem
                break #Added to terminate loop once found
        return False
    
    start = time()
    futures = []
    # used to create the partitions
    steps = 1000000000
    with ProcessPoolExecutor(max_workers=4) as pool:
        for i in range(4):
            # run 4 tasks with a partition, but only *one* solution is needed
            partition = range(i*steps,(i+1)*steps)
            futures.append(pool.submit(m_run, partition))
    
        ### New Code: Start ### 
        for f in as_completed(futures):
            print(f.result())
            if f.result():
                print('break')
                break
    
        for f in futures:
            print(f, 'running?',f.running())
            if f.running():
                f.cancel()
                print('Cancelled? ',f.cancelled())
    
        print('New Instruction Ended at = ', time()-start )
    print('Total Compute Time = ', time()-start )
    

    Update: It is possible to forcefully terminate the concurrent processes via bash, but the consequence is that the main python program will terminate too. If this isn't an issue with you, then try the below code.

    You have to add the below codes between the last 2 print statements to see this for yourself. Note: This code works only if you aren't running any other python3 program.

    import subprocess, os, signal 
    result = subprocess.run(['ps', '-C', 'python3', '-o', 'pid='],
                            stdout=subprocess.PIPE).stdout.decode('utf-8').split()
    print ('result =', result)
    for i in result:
        print('PID = ', i)
        if i != result[0]:
            os.kill(int(i), signal.SIGKILL)
            try: 
               os.kill(int(i), 0)
               raise Exception("""wasn't able to kill the process 
                                  HINT:use signal.SIGKILL or signal.SIGABORT""")
            except OSError as ex:
               continue
    

提交回复
热议问题