-- Back to Index --
To understand the thread, one needs to fully grasp the lifecycle of thread i.e. from start
to finish
.
In Perl
, the only threading model available is ithreads
(interpreter threads), which is implemented via the threads
module. In Perl
, threads are ithreads
, meaning each thread has its own Perl interpreter. Data is not shared by default, and you must explicitly use threads::shared
to share variables. A lock
is used to ensure thread-safe access to shared data.
+-----------------+---------------------------+--------------------------------+
| Feature | Python | Perl |
+-----------------+---------------------------+--------------------------------+
| Memory Sharing | Shared by default | Not shared by default |
| Thread Model | Lightweight (OS-managed) | Heavyweight (Perl interpreter) |
| Thread Safety | Requires explicit locks | Requires explicit locks |
| Data Sharing | Automatic (shared memory) | Explicit (via threads::shared) |
| Performance | Faster (less overhead) | Slower (more overhead) |
+-----------------+---------------------------+--------------------------------+
In this post, I would share how we deal with it in Perl
and Python
.
In Perl
, we would do something like below as the main process creates a new thread.
#!/usr/bin/env perl
use v5.38;
use threads;
sub worker($id) {
say "Thread $id started.";
sleep 5;
say "Thread $id finished.";
}
say "Main process started.";
threads->create(\&worker, 1);
say "Main process finished.";
NOTE: Here threads->create()
actually creates a new thread and immediately start executing it.
Let's see what happens when we run the code:
$ perl create-thread.pl
Main process started.
Main process finished.
Perl exited with active threads:
1 running and unjoined
0 finished and unjoined
0 running and detached
Thread 1 started.
$
You see the output, it tells you the whole story.
Did you notice, the main process didn't wait for the thread to finish?
And in Python
, we would do something like this:
#!/usr/bin/env python3
import threading
import time
def worker(id):
print(f"Thread {id} started.")
time.sleep(5)
print(f"Thread {id} finished.")
print("Main process started.")
thread = threading.Thread(target=worker, args=(1,))
thread.start()
print("Main process finished.")
Now running the above code, we get this:
$ py create-thread.py
Main process started.
Thread 1 started.
Main process finished.
Thread 1 finished.
$
Imagine, if something bad happens in the worker routine, the main process wouldn't know about it.
It just created a new thread and walked away.
We can get around the above issue by joining the newly created thread to the calling process.
This is how you would do in Perl
:
#!/usr/bin/env perl
use v5.38;
use threads;
sub worker($id) {
say "Thread $id started.";
sleep 5;
say "Thread $id finished.";
}
say "Main process started.";
threads->create(\&worker, 1)->join;
say "Main process finished.";
Now if we run the updated code, we get this:
$ perl join-thread.pl
Main process started.
Thread 1 started.
Thread 1 finished.
Main process finished.
$
This is much better, right?
Let's do the same in Python
now:
#!/usr/bin/env python3
import threading
import time
def worker(id):
print(f"Thread {id} started.")
time.sleep(5)
print(f"Thread {id} finished.")
print("Main process started.")
thread = threading.Thread(target=worker, args=(1,))
thread.start()
thread.join()
print("Main process finished.")
Now running the above code, we get this:
$ py join-thread.py
Main process started.
Thread 1 started.
Thread 1 finished.
Main process finished.
$
NOTE: In Perl
, calling $thread->join
returns the result back to the calling process.
Let's update the above example:.
#!/usr/bin/env perl
use v5.38;
use threads;
sub worker($id) {
say "Thread $id started.";
sleep 5;
say "Thread $id finished.";
return $id * 2;
}
say "Main process started.";
my $thread = threads->create(\&worker, 1);
say "Result from thread: ", $thread->join;
say "Main process finished.";
Run the code to see the result.
$ perl result-thread.pl
Main process started.
Thread 1 started.
Thread 1 finished.
Result from thread: 2
Main process finished.
$
OK, can we do the same in Python
?
Yes, you can but not that straight forward. One way is to use queue.Queue
as below:
#!/usr/bin/env python3
import time
import queue
import threading
def worker(id, result):
print(f"Thread {id} started.")
time.sleep(5)
print(f"Thread {id} finished.")
result.put(id * 2)
print("Main process started.")
result = queue.Queue()
thread = threading.Thread(target=worker, args=(1, result))
thread.start()
thread.join()
while not result.empty():
print("Result from thread: ", result.get())
print("Main process finished.")
Let's check the result now:
$ py result-thread.py
Main process started.
Thread 1 started.
Thread 1 finished.
Result from thread: 2
Main process finished.
$
If you really want to detach the newly created thread from the main process then you can do it explicitly.
In Perl
, we would do something like this:
#!/usr/bin/env perl
use v5.38;
use threads;
sub worker($id) {
say "Thread $id started.";
sleep 5;
say "Thread $id finished.";
}
say "Main process started.";
threads->create(\&worker, 1)->detach;
say "Main process finished.";
Run the above code and you should see this:
$ perl detach-thread.pl
Main process started.
Main process finished.
$
In Python
, you create thread as daemon
and it would go away as shown below:
#!/usr/bin/env python3
import threading
import time
def worker(id):
print(f"Thread {id} started.")
time.sleep(5)
print(f"Thread {id} finished.")
print("Main process started.")
thread = threading.Thread(target=worker, args=(1,), daemon=True)
thread.start()
print("Main process finished.")
Now running the above code, we get this:
$ py detach-thread.py
Main process started.
Thread 1 started.
Main process finished.
$
Now the big question, when would you do this?
These are situations when:
1. You want a thread to run independently
2. You want to avoid blocking the main thread
3. You want the thread to clean up automatically
4. You don't want to wait for the thread to finish
-- Back to Index --