Trimax
Trimax

Reputation: 2473

Multithreading doesn't work like I expect it to

I'm learning threading in Python 3.

This is a simple concept example. I want each thread to wait for 5 seconds before it prints, so the call to the thread is only 1 second large, it must return to the main thread.

But the output for my code isn't what I expect.

My code:

import threading, time

class MyThread(threading.Thread):  
    def __init__(self, num):
        threading.Thread.__init__(self)
        self.num = num

    def run(self): 
        time.sleep(5)
        print ("I'm thread number: ", self.num)


print ("I'm the principal thread.")

for i in range(0, 10):
    t = MyThread(i)  
    t.start()      
    t.join(1)     
    print("I'm the principal thread, too.")

The output:

I'm the principal thread.
I'm the principal thread, too.
I'm the principal thread, too.
I'm the principal thread, too.
I'm the principal thread, too.
I'm thread number:  0
I'm the principal thread, too.
I'm thread number:  1
I'm the principal thread, too.
I'm thread number:  2
I'm the principal thread, too.
I'm thread number:  3
I'm the principal thread, too.
I'm thread number:  4
I'm the principal thread, too.
I'm thread number:  5
I'm the principal thread, too.
I'm thread number:  6
I'm thread number:  7
I'm thread number:  8
I'm thread number:  9

The expected output is something like this:

I'm the principal thread.
I'm the principal thread, too.
I'm the principal thread, too.
I'm the principal thread, too.
I'm the principal thread, too.
I'm thread number:  0
I'm the principal thread, too.
I'm the principal thread, too.
I'm the principal thread, too.
I'm the principal thread, too.
I'm thread number:  1
I'm the principal thread, too.
I'm the principal thread, too.
I'm the principal thread, too.
I'm the principal thread, too.
I'm thread number:  2
I'm the principal thread, too.
... 

What am I doing wrong?

Upvotes: 0

Views: 99

Answers (3)

gravetii
gravetii

Reputation: 9624

There is a time lag of one second in your for loop. So, before the spawned thread waits for 5 seconds, the "I'm the principal thread, too." gets printed 4 times. By then, the thread with num=0 has completed waiting for 5 sec. and so it prints.

for i in range(0, 10):
    t = MyThread(i)  
    t.start()      
    t.join(1)     
    print("I'm the principal thread, too.")

In this block, notice the t.join(1). It waits for 1 sec. for the thread 't' to complete, but since the thread is actually waiting for 5 sec. after getting started, it goes ahead with the loop. Thus,

I'm thread number:  0
I'm the principal thread, too.
I'm thread number:  1

this points to the time.sleep(1). The thread number 1 is spawned after 1 sec. the thread number 0 was spawned, and so forth.

The loop runs only 10 times, and thus the "I'm the principal thread, too." prints only 10 times.

I'm the principal thread.
I'm the principal thread, too.
I'm the principal thread, too.
I'm the principal thread, too.
I'm the principal thread, too.
I'm thread number:  0
I'm the principal thread, too.
I'm thread number:  1
I'm the principal thread, too.
I'm thread number:  2
I'm the principal thread, too.
I'm thread number:  3
I'm the principal thread, too.
I'm thread number:  4
I'm the principal thread, too.
I'm thread number:  5
I'm the principal thread, too.

By this time, the loop is over, but the remaining threads are still waiting to print out after waiting for their 5 sec., and thus you see the:

I'm thread number:  6
I'm thread number:  7
I'm thread number:  8
I'm thread number:  9

The problem with the discrepancy in the output is that each thread that is spawned waits for 5 secs. while you call join on it only for a second. Thus, no thread will finish in the allotted 1 sec. If you want to truly wait for the thread generated to complete, you should do this:

for i in range(0, 10):
    t = MyThread(i)  
    if t.is_alive():
        t.join()    
    print("I'm the principal thread, too.")

Upvotes: 1

Arunmu
Arunmu

Reputation: 6901

Based on your output, I think below logic must work


import threading, time

class MyThread(threading.Thread):  
    def __init__(self, num):
        threading.Thread.__init__(self)
        self.num = num

    def run(self): 
        time.sleep(5)
        print ("I'm thread number: ", self.num)


print ("I'm the principal thread.")

for i in range(0, 10):
    t = MyThread(i)  
    t.start()      
    t.join(1)
    ## You join Times out here, since the thread didnt finish in 1 sec 
    ##(its sleeping for 5 secs)
    while t.isAlive():
        time.sleep(1)
        print("I'm the principal thread, too.")

Upvotes: 1

Kevin
Kevin

Reputation: 76194

It sounds like you want the principal thread to keep printing once per second until the other thread finishes. But this won't happen, since the principal thread will give up and move to the next thread after attempting to join once. You ought to keep joining until the thread finishes.

import threading, time

class MyThread(threading.Thread):  
    def __init__(self, num):
        threading.Thread.__init__(self)
        self.num = num

    def run(self): 
        time.sleep(5)
        print ("I'm thread number: ", self.num)


print ("I'm the principal thread.")

for i in range(0, 10):
    t = MyThread(i)  
    t.start()      
    while True:
        t.join(1)
        print("I'm the principal thread, too.")
        if not t.isAlive(): break

Upvotes: 1

Related Questions