MultiThreading in Python

Multi-threading

Create sub-thread

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import threading

# this is target function
def run(name):
print('Current task is', name)

if __name__ == '__main__':
# create sub-thread
t1 = threading.Thread(target=run, args=('Thread 1',))
t2 = threading.Thread(target=run, args=('Thread 2',))

# main thread waits for sub-thread
t1.join()
t2.join()

print('Exit')

Custom sub-thread

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import threading

# customize thread function
class MyThread(threading.Thread):
def __init__(self, name, n):
super(MyThread, self).__init__()
self.name = name
self.n = n
def run(self):
print('Current task is', self.name)
while self.n > 0:
self.n -= 1

if __name__ == '__main__':
t1 = MyThread('Thread 1', 100000)
t2 = MyThread('Thread 2', 100000)

t1.start()
t2.start()

# main thread will wait for sub-thread
t1.join()
t2.join()

print('Exit')

Lock

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import time
import threading

# create lock
mutex = threading.Lock()

num = 0

class LockThread(threading.Thread):
def run(self):
global num # introduce global variable
time.sleep(1)
if mutex.acquire(timeout=1): # acquire lock (only wait 1 second)
num += 1 # change global variable
msg = '{0}: num={1}'.format(self.name, num)
print(msg)
mutex.release() # release lock

if __name__ == '__main__':
# add lock to sub-thread
for i in range(5):
t = LockThread()
t.start()

Reentrant lock

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import time
import threading

# create lock
mutex = threading.RLock()

num = 0

class LockThread(threading.Thread):
def run(self):
global num # introduce global variable
time.sleep(1)
if mutex.acquire(timeout=1): # acquire lock (only wait 1 second)
num += 1 # change global variable
msg = '{0}: num={1}'.format(self.name, num)
print(msg)
time.sleep(1)
mutex.acquire() # multi-lock can be acquired
mutex.release() # resource is free only after all locks are released
mutex.release()

if __name__ == '__main__':
# add lock to sub-thread
for i in range(5):
t = LockThread()
t.start()

End main thread without waiting for sub-thread

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import threading

# customize thread function
class MyThread(threading.Thread):
def __init__(self, name, n):
super(MyThread, self).__init__()
self.name = name
self.n = n
def run(self):
print('Current task is', self.name)
while self.n > 0:
self.n -= 1

if __name__ == '__main__':
t1 = MyThread('Thread 1', 10000000)
t2 = MyThread('Thread 2', 10000000)

# main thread will not wait for sub-thread
t1.setDaemon(True) # must be set before start()
t2.setDaemon(True)

t1.start()
t2.start()

print('Exit')

Timer

1
2
3
4
5
6
7
from threading import Timer

def show():
print("Hello world!")

t = Timer(1, show) # run after 1 second
t.start()

Multi-processing

Multi-processing is similar to multi-threading

Create sub-process

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from multiprocessing import Process

def show(name):
print('Process name is', name)

class MyProcess(Process):
def __init__(self, name):
super(MyProcess, self).__init__()
self.name = name
def run(self):
print('Process name is', self.name)

if __name__ == '__main__':
proc = Process(target=show, args=('Process -1',))
proc.start()
proc.join()

for i in range(5):
p = MyProcess('Process {0}'.format(i))
p.start()

for i in range(5):
p.join()

Pool

You do not have to create sub-processes one by one.

1
2
3
4
5
6
7
8
9
10
11
12
from multiprocessing import Pool

def show(num):
print('num: {0}'.format(num))

if __name__ == '__main__':
pool = Pool(processes=4) # max concurrent process <= num of physical cores
for i in range(5):
pool.apply_async(func=show, args=(i,))
print('===== apply_async =====')
pool.close() # close pool after all sub-processes are finished
pool.join() # main process will wait for sub-process (after close())