A somewhat clumsy ascii-art to demonstrate the mechanism:
The join() is presumably called by the main-thread. It could also be called by another thread, but would needlessly complicate the diagram.
join-calling should be placed in the track of the main-thread, but to express thread-relation and keep it as simple as possible, I choose to place it in the child-thread instead.
without join:
+---+---+------------------ main-thread
| |
| +........... child-thread(short)
+.................................. child-thread(long)
with join
+---+---+------------------***********+### main-thread
| | |
| +...........join() | child-thread(short)
+......................join()...... child-thread(long)
with join and daemon thread
+-+--+---+------------------***********+### parent-thread
| | | |
| | +...........join() | child-thread(short)
| +......................join()...... child-thread(long)
+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, child-thread(long + daemonized)
'-' main-thread/parent-thread/main-program execution
'.' child-thread execution
'#' optional parent-thread execution after join()-blocked parent-thread could
continue
'*' main-thread 'sleeping' in join-method, waiting for child-thread to finish
',' daemonized thread - 'ignores' lifetime of other threads;
terminates when main-programs exits; is normally meant for
join-independent tasks
So the reason you don't see any changes is because your main-thread does nothing after your join.
You could say join is (only) relevant for the execution-flow of the main-thread.
If, for example, you want to concurrently download a bunch of pages to concatenate them into a single large page, you may start concurrent downloads using threads, but need to wait until the last page/thread is finished before you start assembling a single page out of many. That's when you use join().
A somewhat clumsy ascii-art to demonstrate the mechanism:
The join() is presumably called by the main-thread. It could also be called by another thread, but would needlessly complicate the diagram.
join-calling should be placed in the track of the main-thread, but to express thread-relation and keep it as simple as possible, I choose to place it in the child-thread instead.
without join:
+---+---+------------------ main-thread
| |
| +........... child-thread(short)
+.................................. child-thread(long)
with join
+---+---+------------------***********+### main-thread
| | |
| +...........join() | child-thread(short)
+......................join()...... child-thread(long)
with join and daemon thread
+-+--+---+------------------***********+### parent-thread
| | | |
| | +...........join() | child-thread(short)
| +......................join()...... child-thread(long)
+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, child-thread(long + daemonized)
'-' main-thread/parent-thread/main-program execution
'.' child-thread execution
'#' optional parent-thread execution after join()-blocked parent-thread could
continue
'*' main-thread 'sleeping' in join-method, waiting for child-thread to finish
',' daemonized thread - 'ignores' lifetime of other threads;
terminates when main-programs exits; is normally meant for
join-independent tasks
So the reason you don't see any changes is because your main-thread does nothing after your join.
You could say join is (only) relevant for the execution-flow of the main-thread.
If, for example, you want to concurrently download a bunch of pages to concatenate them into a single large page, you may start concurrent downloads using threads, but need to wait until the last page/thread is finished before you start assembling a single page out of many. That's when you use join().
Straight from the docs
join([timeout]) Wait until the thread terminates. This blocks the calling thread until the thread whose join() method is called terminates – either normally or through an unhandled exception – or until the optional timeout occurs.
This means that the main thread which spawns t and d, waits for t to finish until it finishes.
Depending on the logic your program employs, you may want to wait until a thread finishes before your main thread continues.
Also from the docs:
A thread can be flagged as a “daemon thread”. The significance of this flag is that the entire Python program exits when only daemon threads are left.
A simple example, say we have this:
def non_daemon():
time.sleep(5)
print 'Test non-daemon'
t = threading.Thread(name='non-daemon', target=non_daemon)
t.start()
Which finishes with:
print 'Test one'
t.join()
print 'Test two'
This will output:
Test one
Test non-daemon
Test two
Here the master thread explicitly waits for the t thread to finish until it calls print the second time.
Alternatively if we had this:
print 'Test one'
print 'Test two'
t.join()
We'll get this output:
Test one
Test two
Test non-daemon
Here we do our job in the main thread and then we wait for the t thread to finish. In this case we might even remove the explicit joining t.join() and the program will implicitly wait for t to finish.
Videos
i hope you guys can help me because has been two days that i on this thing. probably i'm stupid, but i can't get this. so, i'm studying this piece of code (taken from this video: https://youtu.be/StmNWzHbQJU) and i just modified the function called by Threading class.
import threading
from time import sleep
from random import choice
def doThing():
threadId = choice([i for i in range(1000)]) # just 'names' a thread
while True:
print(f"{threadId} ", flush=True)
sleep(3)
threads = []
for i in range(50):
t = threading.Thread(target=doThing, daemon = False)
threads.append(t)
for i in range(50):
threads[i].start()
for i in range(50):
threads[i].join()the problems are basically 3:
-
i can't stop the program with ctrl+c like he does in the video. i tried by set daemon = False or delet the .join() loop, nothing work, neither in the Idle interpeter neithe in the command line and powershell (i'm on windows);
-
as i said,i tried to set daemon=False and to delete the .join() loop, but nothing change during the execution so i'm a little bit confused on what "daemon" and ".join()" actually does;
-
the function doThing() is endless so the join() shouldn't be useful. And i don't understand why there are two "for" loops, one for start() and one for join(). Can't they be into the same "for" cycle?
-
last thing, the print output is totally different between Idle and powershell: in Idle i get some lines with different numbers, in the powershell i get only one number per line (look at the images):https://ibb.co/HtMr9gf, https://ibb.co/Y8gzDtw, but in visual code, which use powershell too, i get this: https://ibb.co/X82vY3v
can you help me to understand this please? i'm really confused. thank you a lot