Python Learning - Python Threads

Posted by mart on Tue, 18 Jun 2019 20:02:52 +0200

1. Thread Creation

 1 #Method 1: Pass the method to be executed as a parameter to Thread Construction methods
 2 import threading
 3 import time
 4 
 5 def show(arg):
 6     time.sleep(2)
 7     print('thread' + str(arg))
 8 
 9 for i in range(10):
10     t = threading.Thread(target=show,args=(i,))
11     time.sleep(2)
12     t.start()
13 
14 #Method 2: From Thread Inherit and Override run()
15 class MyThread(threading.Thread):
16     def __init__(self,num):
17         threading.Thread.__init__(self)
18         self.num = num
19 
20     def run(self)):#Define the function to run for each thread
21         print("running on number:%s" %self.num)
22         time.sleep(3)
23 
24 
25 if __name__ ==  '__main__':
26     t1 = MyThread(1)
27     t2 = MyThread(2)
28     t1.start()
29     time.sleep(3)
30     t2.start()

Notes:
Thread(group=None,target=None,name=None,args=(),kwargs={})
Group: Thread group, not yet implemented, prompted for library reference must be None
target: Method to execute
Name: Thread name
args/kwargs: To pass in method parameters, args and kwargs are actually two-choice parameters
#Instance Method
isAlive(): Returns whether the thread is running
get/setName(name): Gets/sets the thread name
is/setDaemon(bool): Gets/sets whether to daemon threads.Initial values inherit from the thread that created the thread and terminate when no non-daemon thread is still running
start(): Start the thread
join([timeout]): Blocks threads in the current context.

2. Python multithreading usage

 1 import threading
 2 from time import ctime,sleep
 3 
 4 def music(func):
 5     for i in range(2):
 6         print("I was listening to %s. %s" %(func,ctime()))
 7         sleep(1)
 8 def move(func):
 9     for i in range(2):
10         print("I was at the %s! %s" %(func,ctime()))
11         sleep(5)
12 
13 threads = []
14 t1 = threading.Thread(target=music,args=('Once Upon a Time',))
15 threads.append(t1)
16 t2 = threading.Thread(target=move,args=('Transformers',))
17 threads.append(t2)
18 
19 if __name__ == '__main__':
20     for t in threads:
21         t.setDaemon(True)
22         t.start()
23 
24     print("all over %s" %ctime())

Note:

threads = []

t1 = threading.Thread(target=music,args=('fairy town',))

threads.append(t1)

Create threads array, create thread t1, use threading.Thread() method, call music method target=music, args method passes music.Load the created thread T1 into the threads array.

Next, create thread t2 in the same way and load t2 into the threads array.

for t in threads:

  t.setDaemon(True)

  t.start()

Finally, the array is traversed through a for loop.(Array is loaded with t1 and t2 threads)

setDaemon()

setDaemon(True) declares a thread as a daemon thread and must be set before the start() method call. If it is not set as a daemon, the program will hang indefinitely.After the child thread starts, the parent thread continues to execute. When the parent thread finishes executing the last statement print "all over%s"%ctime(), it exits without waiting for the child thread, and the child thread ends at the same time.

SerDeamon (False) (default) foreground thread. The foreground thread is also in progress during the main thread execution. After the main thread has finished executing, the main thread stops waiting for the foreground thread to finish executing.

Run result:

I was listening to Once Upon a Time. Thu Jun 22 23:23:07 2017
I was at the Transformers! Thu Jun 22 23:23:07 2017
all over Thu Jun 22 23:23:07 2017

Subthreads (muisc, move) and main threads (print "all over%s"%ctime()) are started at the same time from the execution results, but they also terminate because the main thread finishes execution.(

Adjustment procedure:

 

1 if __name__ == '__main__':
2     for t in threads:
3         t.setDaemon(True)
4         t.start()
5     
6     t.join()
7 
8     print "all over %s" %ctime()

The join() method has been added to wait for the thread to terminate.Join() is used to block the parent thread of a child thread until it has finished running.

The join() method is located outside the for loop, which means that you must wait for both processes in the for loop to finish before executing the main process.

Run result:

1 ##################### Run Result ################################
2 I was listening to fairy tale town. Thu Jun 22 23:34:22 2017
 3 I was at the Transformers! Thu Jun 22 23:34:22 2017
 4 I was listening to fairy tale town. Thu Jun 22 23:34:23 2017
 5 I was at the Transformers! Thu Jun 22 23:34:27 2017
6 all over Thu Jun 22 23:34:32 2017

From the time of the result, we can see that each song waits for one second, movies wait for five seconds, but they are synchronized, the total time is five seconds

3. Thread Lock (LOCK,RLOCK)
Because threads are randomly scheduled and each thread may execute only n executions, dirty data may appear when multiple threads modify the same data at the same time, a thread lock occurs - allowing one thread to perform operations at a time.

Lock is the lowest level of synchronization instruction available.Lock is not owned by a specific thread when it is locked.Lock has two states - locked and unlocked, and two basic methods.

You can think of Lock as having a lock pool that puts a thread in the pool when a thread requests a lock until it gets a lock and exits the pool.Threads in the pool are in a synchronous blocked state in the state diagram.*

RLock is a synchronous instruction that can be requested multiple times by the same thread.RLock uses the concepts of Owned Threads and Recursive Hierarchy, and when locked, RLock is owned by a thread.Threads with RLocks can call acquire() again, and release() needs to be called the same number of times to release a lock.

You can think of RLock as containing a lock pool and a counter with an initial value of 0, each time acquire()/release() is called successfully, the counter will + 1/-1, and the lock will be unlocked at 0.

In short: Lock is global and Rlock is thread.

1, no locks used

 1 import threading
 2 import time
 3 
 4 num = 0
 5 
 6 def show(arg):
 7     global num
 8     time.sleep(1)
 9     num +=1
10     print(num)
11 
12 for i in range(10):
13     t = threading.Thread(target=show, args=(i,))
14     t.start()
15 
16 print('main thread stop')

Multiple runs can cause confusion.This is the ideal scenario for using locks.

2. Use locks

 1 import threading
 2 import time
 3 
 4 num = 0
 5 lock = threading.RLock()
 6 
 7 # call acquire([timeout])When the thread is blocked,
 8 # Until locked or until timeout Seconds later ( timeout Optional parameters).
 9 # Returns whether a lock has been acquired.
10 def show(arg):
11     lock.acquire()
12     global num
13     time.sleep(1)
14     num +=1
15     print(num)
16     lock.release()
17 
18 for i in range(10):
19     t = threading.Thread(target=show, args=(i,))
20     t.start()
21 
22 print('main thread stop')

With the lock, the numbers will be printed step by step without being confused by the congestion!


4. Semaphore

Mutual exclusion locks allow only one thread to change data at the same time, while Semaphore allows a certain number of threads to change data at the same time, such as all three pits in the toilet, which allows a maximum of three people to go to the toilet, and the people behind it can only wait for someone to come out before entering.

 1 import threading, time
 2 
 3 def run(n):
 4     semaphore.acquire()
 5     time.sleep(3)
 6     print("run the thread: %s" % n)
 7     semaphore.release()
 8 
 9 if __name__ == '__main__':
10     num = 0
11     semaphore = threading.BoundedSemaphore(5)  # Allow up to five threads to run simultaneously
12     for i in range(20):
13         t = threading.Thread(target=run, args=(i,))
14         t.start()

5. Events

Events for Python threads are mainly used by the main thread to control the execution of other threads. Events provide three main methods: set, wait, clear

Mechanisms for event handling: A "Flag" is defined globally. If the "Flag" value is False, the program will block when it executes the event.wait method. If the "Flag" value is True, the event.wait method will not block anymore.

clear: Set Flag to False

set: set Flag to True

Communication between threads using threading.Event

threading.Event causes a thread to wait for notifications from other threads to pass this event to the thread object, which has a flag built in by default and has an initial value of False.
Once the thread enters the wait state through the wait() method until another thread calls the Event's set() method to set the built-in flag to True,
This Event notifies all waiting threads to resume running.

 1 import threading
 2 
 3 def do(event):
 4     print('start')
 5     event.wait()
 6     print('end')
 7 
 8 event_obj = threading.Event()
 9 
10 for i in range(10):
11     t = threading.Thread(target=do, args=(event_obj,))
12     t.start()
13 
14 event_obj.clear() #Continue blocking
15 
16 inp = input('input:')
17 if inp == 'true':
18     event_obj.set()  # awaken

6. Conditions
The so-called conditional variable, that is, this mechanism allows threads to access related data only after certain conditions are met!

It is done using the Condition class, and since it can also be used like a lock mechanism, it also has the acquire and release methods, and it also has the wait, notify, notifyAll methods

A simple production consumer model, which controls the increase or decrease of the number of products through conditional variables, calls a producer product is + 1, and calls a consumer product are -1.
Use the Condition class to do this, and since it can also be used like a lock mechanism, it also has the acquire and release methods, and it also has
wait, notify, notifyAll method.
 1 import threading
 2 import  time
 3 
 4 # Product Class
 5 class Goods:
 6     def __init__(self):
 7         self.count = 0
 8 
 9     def add(self, num=1):
10         self.count += num
11 
12     def sub(self):
13         if self.count >= 0:
14             self.count -= 1
15 
16     def empty(self):
17         return self.count <= 0
18 
19 # Producer
20 class Producer(threading.Thread):
21     def __init__(self, condition, goods, sleeptime=1):
22         threading.Thread.__init__(self)
23         self.cond = condition
24         self.goods = goods
25         self.sleeptime = sleeptime
26 
27     def run(self):
28         cond = self.cond
29         goods = self.goods
30         while True:
31             # Lock resources
32             cond.acquire()
33             goods.add()
34             print("Product Quantity:", goods.count, "Producer Threads")
35             # Wake up all waiting threads -> It's really waking up the consumer process
36             cond.notifyAll()
37             # Unlock Resources
38             cond.release()
39             time.sleep(self.sleeptime)
40 
41 
42 # Consumer
43 class Consumer(threading.Thread):
44     def __init__(self, condition, goods, sleeptime=2):
45         threading.Thread.__init__(self)
46         self.cond = condition
47         self.goods = goods
48         self.sleeptime = sleeptime
49 
50     def run(self):
51         cond = self.cond
52         goods = self.goods
53 
54         while True:
55             time.sleep(self.sleeptime)
56             # Lock resources
57             cond.acquire()
58             # Allow threads to wait if no product exists
59             while goods.empty():
60                 cond.wait()
61             goods.sub()
62             print("Product Quantity:", goods.count, "Consumer Threads")
63             
64 
65 g = Goods()
66 c = threading.Condition()
67 pro = Producer(c, g)
68 pro.start()
69 con = Consumer(c, g)
70 con.start()

7. Timer

 1 import threading
 2 def SayHello():
 3     print("hello world!")
 4     t=threading.Timer(3,SayHello)
 5     t.start()
 6 def other_func():
 7     print("let me running!")
 8     t=threading.Timer(1,other_func)
 9     t.start()
10 
11 if __name__ == "__main__":
12     SayHello()
13     other_func()

 

 

Topics: Python