Will different threads end at the same time as the first one to finish?

依然范特西╮ 提交于 2020-05-02 04:42:44

问题


I'm new to thread in python, i have a question that, supposed i start 3 threads like below, each one takes care of 1 different task:

def start( taskName, delay):
   // do somthing with each taskName

# Create two threads as follows
try:
   thread.start_new_thread( start, ("task1", ) )
   thread.start_new_thread( start, ("task2", ) )
   thread.start_new_thread( start, ("task3", ) )
except:
   print "Error: unable to start thread"

Supposed that for each "start", it takes around 10-15 seconds to finish depending on each taskName it is. My question is that, if task 1 finishes in 12 seconds, tasks 2 in 10secs and task 3 in 15 seconds. Will task 2 finish then close and leave task 1 and task 3 to run till finish, or will task 2 force task 1 and 3 to close after task 2 is finished?

Are there any arguments that we can pass to the start_new_thread method in order to archive 2 of the things that I have mentioned above: 1. First to finish forces the rest to close. 2. Each one finish individually.

Thank you


回答1:


As Max Noel already mentioned, it is advised to use the Thread class instead of using start_new_thread.

Now, as for your two questions:

1. First to finish forces the rest to close You will need two important things: a shared queue that the threads can put their ID in once they are done. And a shared Event that will signal all threads to stop working when it is triggered. The main thread will wait for the first thread to put something in the queue and will then trigger the event to stop all threads.

import threading
import random
import time
import Queue

def work(worker_queue, id, stop_event):
    while not stop_event.is_set():
        print "This is worker", id

        # do stuff
        time.sleep(random.random() * 5)

        # put worker ID in queue
        if not stop_event.is_set():
            worker_queue.put(id)

        break

# queue for workers
worker_queue = Queue.Queue()

# indicator for other threads to stop
stop_event = threading.Event()

# run workers
threads = []
threads.append(threading.Thread(target=work, args=(worker_queue, 0, stop_event)))
threads.append(threading.Thread(target=work, args=(worker_queue, 1, stop_event)))
threads.append(threading.Thread(target=work, args=(worker_queue, 2, stop_event)))

for thread in threads:
    thread.start()

# this will block until the first element is in the queue
first_finished = worker_queue.get()

print first_finished, 'was first!'

# signal the rest to stop working
stop_event.set()

2. Each finish individually Now this is much easier. Just call the join method on all Thread objects. This will wait for each thread to finish.

for thread in threads:
    thread.start()

for thread in threads:
    thread.join()

Btw, the above code is for Python 2.7. Let me know if you need Python 3




回答2:


First off, don't use start_new_thread, it's a low-level primitive. Use the Thread class in the threading module instead.

Once you have that, Thread instances have a .join() method, which you can call from another thread (your program's main thread) to wait for them to terminate.

t1 = Thread(target=my_func)
t1.start()
# Waits for t1 to finish.
t1.join()



回答3:


All threads will terminate when the process terminates. Thus, if your main program ends after the try..except, then all three threads may get terminated prematurely. For example:

import thread
import logging
import time
logger = logging.getLogger(__name__)

def start(taskname, n):
    for i in range(n):
        logger.info('{}'.format(i))
        time.sleep(0.1)

if __name__ == '__main__':
    logging.basicConfig(level=logging.DEBUG,
                        format='[%(asctime)s %(threadName)s] %(message)s',
                        datefmt='%H:%M:%S')
    try:
        thread.start_new_thread( start, ("task1", 10) )
        thread.start_new_thread( start, ("task2", 5) )
        thread.start_new_thread( start, ("task3", 8) )
    except Exception as err:
        logger.exception(err)

may print something like

[14:15:16 Dummy-3] 0
[14:15:16 Dummy-1] 0

In contrast, if you place

time.sleep(5)

at the end of the script, then you see the full expected output from all three threads.


Note also that the thread module is a low-level module; unless you have a particular reason for using it, most often people use the threading module which implements more useful features for dealing with threads, such as a join method which blocks until the thread has finished. See below for an example.


The docs state:

When the function returns, the thread silently exits. When the function terminates with an unhandled exception, a stack trace is printed and then the thread exits (but other threads continue to run).

Thus, by default, when one thread finishes, the others continue to run. The example above also demonstrates this.


To make all the threads exit when one function finishes is more difficult. One thread can not kill another thread cleanly (e.g., without killing the entire process.)

Using threading, you could arrange for the threads to set a variable (e.g. flag) to True when finished, and have each thread check the state of flag periodically and quit if it is True. But note that the other threads will not necessarily terminate immediately; they will only terminate when they next check the state of flag. If a thread is blocked, waiting for I/O for instance, then it may not check the flag for a considerable amount of time (if ever!).

However, if the thread spends most of its time in a quick loop, you could check the state of flag once per iteration:

import threading
import logging
import time
logger = logging.getLogger(__name__)

def start(taskname, n):
    global flag
    for i in range(n):
        if flag:
            break
        logger.info('{}'.format(i))
        time.sleep(0.1)
    else:
        # get here if loop finishes without breaking
        logger.info('FINISHED')
    flag = True

if __name__ == '__main__':
    logging.basicConfig(level=logging.DEBUG,
                        format='[%(asctime)s %(threadName)s] %(message)s',
                        datefmt='%H:%M:%S')
    threads = list()
    flag = False
    try:
        threads.append(threading.Thread(target=start, args=("task1", 10) ))
        threads.append(threading.Thread(target=start, args=("task2", 5) ))
        threads.append(threading.Thread(target=start, args=("task3", 8) ))
    except Exception as err:
        logger.exception(err)

    for t in threads:
        t.start()
    for t in threads:
        # make the main process wait until all threads have finished.
        t.join()       


来源:https://stackoverflow.com/questions/27626390/will-different-threads-end-at-the-same-time-as-the-first-one-to-finish

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!