Use of threading.Thread.join()

40,508

Solution 1

A call to thread1.join() blocks the thread in which you're making the call, until thread1 is finished. It's like wait_until_finished(thread1).

For example:

import time

def printer():
    for _ in range(3):
        time.sleep(1.0)
        print "hello"

thread = Thread(target=printer)
thread.start()
thread.join()
print "goodbye"

prints

hello
hello
hello
goodbye

—without the .join() call, goodbye would come first and then 3 * hello.

Also, note that threads in Python do not provide any additional performance (in terms of CPU processing power) because of a thing called the Global Interpreter Lock, so while they are useful for spawning off potentially blocking (e.g. IO, network) and time consuming tasks (e.g. number crunching) to keep the main thread free for other tasks, they do not allow you to leverage multiple cores or CPUs; for that, look at multiprocessing which uses subprocesses but exposes an API equivalent to that of threading.

PLUG: ...and it is also for the above reason that, if you're interested in concurrency, you might also want to look into a fine library called Gevent, which essentially just makes threading much easier to use, much faster (when you have many concurrent activities) and less prone to concurrency related bugs, while allowing you to keep coding the same way as with "real" threads. Also Twisted, Eventlet, Tornado and many others, are either equivalent or comparable. Furthermore, in any case, I'd strongly suggest reading these classics:

Solution 2

I modified the code so that you will understand how exactly join works. so run this code with comments and without comments and observe the output for both.

val = 0

def increment(msg,sleep_time):
   global val 
   print "Inside increment"
   for x in range(10):
       val += 1
       print "%s : %d\n" % (msg,val)
       time.sleep(sleep_time)

thread1 = threading.Thread(target=increment, args=("thread_01",0.5))
thread2 = threading.Thread(target=increment, args=("thread_02",1))
thread1.start()
#thread1.join()
thread2.start()
#thread2.join()

Solution 3

As the relevant documentation states, join makes the caller wait until the thread terminates.

In your case, the output is the same because join doesn't change the program behaviour - it's probably being used to exit the program cleanly, only when all the threads have terminated.

Share:
40,508

Related videos on Youtube

Pratik Singhal
Author by

Pratik Singhal

Hi, I am currently working as a software development engineer at Amazon India. I am a fullstack developer and have lot of experience in developing end to end applications (mobile app, web app and backend) for multiple different projects.

Updated on December 02, 2020

Comments

  • Pratik Singhal
    Pratik Singhal over 3 years

    I am new to multithreading in python and trying to learn multithreading using threading module. I have made a very simple program of multi threading and i am having trouble understanding the threading.Thread.join method.

    Here is the source code of the program I have made

    import threading
    
    val = 0
    
    def increment():
       global val 
       print "Inside increment"
       for x in range(100):
           val += 1
       print "val is now {} ".format(val)
    
    thread1 = threading.Thread(target=increment, args=())
    thread2 = threading.Thread(target=increment, args=())
    thread1.start()
    #thread1.join()
    thread2.start()
    #thread2.join() 
    

    What difference does it make if I use

    thread1.join()
    thread2.join()
    

    which I have commented in the above code? I ran both the source codes (one with comments and the one without comments) but the output is the same.

    • Vivek
      Vivek over 10 years
    • David Schwartz
      David Schwartz over 10 years
      Do you want your code to work because it is correct or by accident?
    • Pratik Singhal
      Pratik Singhal over 10 years
      @Vivek Although the title of the question asked is almost the same, my question is a little simpler and asks for just a basic working of the join() function.As I am new to threading, I couldn't understand the answer given to the link pointed out by you.Therefore, I thought it would be better to ask a new simple question.
    • Erik Kaplun
      Erik Kaplun over 10 years
      The answer there was even a bit hard to understand for me.
  • erewok
    erewok over 10 years
    "Also, note that threads in Python do not provide any additional performance because of a thing called the Global Interpreter Lock..." This is an overly broad generalization and false, as a result. Threading is perfectly fine for I/O bound tasks and will certainly provide performance benefits there. There are numerous threads discussing this point.
  • Erik Kaplun
    Erik Kaplun over 10 years
    @erewok: You must have missed the part where I say "while they are useful for spawning off potentially blocking and time consuming" and "they do not allow you to leverage multiple cores or CPUs"... in any case, I've updated my answer to be more clear on this.
  • erewok
    erewok over 10 years
    I think the edit is useful for clarifying where threads may be useful. Thanks for including it.
  • Pratik Singhal
    Pratik Singhal over 10 years
    thanks for the answer, your code clearly shows the difference between using join() and not using it
  • Sadanand Upase
    Sadanand Upase over 6 years
    I still cant get why Python did not opt for a better name instead of 'join'? Wouldn't 'wait_until_finished' or something on similar line be more intuitive?