Article catalog
As for what is multithreading, I don't need to record. Baidu is a pile of random notes, mainly recording notes that are useful to me. Here I mainly use the threading module
Multithreading (review)
General creation method (not commonly used)
Note: the args parameter is a tuple. If there is only one parameter, don't forget the comma after it
import threading import time def run(n): print("hello", n) time.sleep(1) if __name__ == '__main__': t1 = threading.Thread(target=run, args=("threading1",)) t2 = threading.Thread(target=run, args=("threading2",)) t1.start() t2.start()
Custom thread (inherited threading.Thread)
Essence: Refactoring run method
import threading import time class MyThread(threading.Thread): def __init__(self, item): threading.Thread.__init__(self) self.item = item def run(self): print("threadingTask", self.item) time.sleep(1) if __name__ == "__main__": t1 = MyThread("threading1") t2 = MyThread("threading2") t1.start() t2.start()
Advanced knowledge
Daemons
Here, setDaemon(True) is used to turn all the sub threads into the main thread's Guardian threads, so when the main process ends, the sub threads will also end. So when the main thread ends, the whole program exits.
import threading import time class MyThread(threading.Thread): def __init__(self, item,t): threading.Thread.__init__(self) self.item = item self.t = t def run(self): print("threadingTask", self.item) time.sleep(self.t) print(self.item+"end") if __name__ == "__main__": t1 = MyThread("threading1",1) t2 = MyThread("threading2",10) t3 = MyThread("threading3",100) t2.setDaemon(True) t3.setDaemon(True) t1.start() t2.start() t3.start()
Operation result:
After setting the daemons, when the main thread ends, the sub thread will end immediately and will not execute any more
Let the main thread wait for the child thread to end
Of course, setting thread daemons in the following example is of little significance, just to emphasize that setting subprocesses as daemons must be set before start()
import threading import time class MyThread(threading.Thread): def __init__(self, item, t): threading.Thread.__init__(self) self.item = item self.t = t def run(self): print("threadingTask", self.item) time.sleep(self.t) print(self.item + "end") if __name__ == "__main__": t1 = MyThread("threading1", 1) t2 = MyThread("threading2", 2) t3 = MyThread("threading3", 3) t2.setDaemon(True) t3.setDaemon(True) t1.start() t2.start() t3.start() t1.join() t2.join() t3.join()
Thread sharing global variables
Thread is the execution unit of a process, and process is the smallest unit of resources allocated by the system, so multithreads in the same process share resources. And threads can share global variables. I don't know what to say. I copied a code online for review
import threading
import time
g_num = 100
def work1():
global g_num
for i in range(3):
g_num += 1
print("in work1 g_num is : %d" % g_num)
def work2():
global g_num
print("in work2 g_num is : %d" % g_num)
if name == 'main':
t1 = threading.Thread(target=work1)
t1.start()
time.sleep(1)
t2 = threading.Thread(target=work2)
t2.start()
Thread synchronization
The following parts are from Rookie tutorial
If multiple threads modify a data together, unexpected results may appear. In order to ensure the correctness of data, it is necessary to synchronize multiple threads. The advantage of multithreading is that you can run multiple tasks at the same time (at least it feels like this). However, when threads need to share data, there may be data synchronization problems.
Consider a situation where all elements in a list are 0, the thread "set" changes all elements from back to front to 1, and the thread "print" reads the list from front to back and prints.
Then, when the thread "set" starts to change, the thread "print" will print the list, and the output will be half 0 and half 1, which is the data out of sync. To avoid this situation, the concept of lock is introduced.
There are two states of a lock - locked and unlocked. Every time a thread such as "set" wants to access shared data, it must obtain lock first; if another thread such as "print" has obtained lock, then let thread "set" pause, that is, synchronous block; after thread "print" access is completed and the lock is released, let thread "set" continue.
After this kind of processing, when printing the list, you can either output 0 or 1 completely, and there will be no awkward scene of half 0 and half 1 again.
mutex
#!/usr/bin/python3 import threading import time class myThread(threading.Thread): def __init__(self, threadID, name, counter): threading.Thread.__init__(self) self.threadID = threadID self.name = name self.counter = counter def run(self): print("Open thread: " + self.name) # Get lock for thread synchronization threadLock.acquire() print_time(self.name, self.counter, 3) # Release lock, open next thread threadLock.release() def print_time(threadName, delay, counter): while counter: time.sleep(delay) print("%s: %s" % (threadName, time.ctime(time.time()))) counter -= 1 threadLock = threading.Lock() threads = [] # Create a new thread thread1 = myThread(1, "Thread-1", 1) thread2 = myThread(2, "Thread-2", 2) # Start a new thread thread1.start() thread2.start() # Add thread to thread list threads.append(thread1) threads.append(thread2) # Wait for all threads to complete for t in threads: t.join() print("Exit main thread")
Recursive lock
The usage as like as two peas of RLcok class is Lock class, but it supports nesting. RLcok classes are usually used when multiple locks are not released.
#!/usr/bin/python3 import threading import time class myThread(threading.Thread): def __init__(self, threadID, name, counter): threading.Thread.__init__(self) self.threadID = threadID self.name = name self.counter = counter def run(self): print("Open thread: " + self.name) # Get lock for thread synchronization threadLock.acquire() print_time(self.name, self.counter, 3) # Release lock, open next thread threadLock.release() def print_time(threadName, delay, counter): while counter: time.sleep(delay) print("%s: %s" % (threadName, time.ctime(time.time()))) counter -= 1 threadLock = threading.RLock() threads = [] # Create a new thread thread1 = myThread(1, "Thread-1", 1) thread2 = myThread(2, "Thread-2", 2) # Start a new thread thread1.start() thread2.start() # Add thread to thread list threads.append(thread1) threads.append(thread2) # Wait for all threads to complete for t in threads: t.join() print("Exit main thread")
BoundedSemaphore class
Mutex allows 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
#!/usr/bin/python3 import threading import time class myThread(threading.Thread): def __init__(self, threadID, name, counter, semaphore): threading.Thread.__init__(self) self.threadID = threadID self.name = name self.counter = counter self.semaphore = semaphore def run(self): print("Open thread: " + self.name) semaphore.acquire() print_time(self.name, self.counter, 3) semaphore.release() def print_time(threadName, delay, counter): while counter: time.sleep(delay) print("%s: %s" % (threadName, time.ctime(time.time()))) counter -= 1 semaphore = threading.BoundedSemaphore(2) threads = [] for i in range(3): t = myThread(i + 1, f"Thread-{i + 1}", i + 1,semaphore) threads.append(t) for i in threads: i.start() while threading.active_count() != 1: pass else: print('-----all threads done-----')
Event (event class)
This part is from [blog], thank you for your blog( https://www.cnblogs.com/luyuze95/p/11289143.html#threading%E6%A8%A1%E5%9D%97)
python thread events are used by the main thread to control the execution of other threads. Event is a simple thread synchronization object, which mainly provides the following methods:
clear set flag to False
Set set flag to True
is_set to determine whether the flag is set
wait will listen to the flag all the time. If no flag is detected, it will be blocked all the time
Event handling mechanism: a "flag" is defined globally. When the flag value is "False", then event.wait() will block, when the flag value is "True", then event.wait() is no longer blocked.
#Using Event class to simulate traffic light import threading import time event = threading.Event() def lighter(): count = 0 event.set() #The initial value is green while True: if 5 < count <=10 : event.clear() # Red light, clear flag print("\33[41;1mred light is on...\033[0m") elif count > 10: event.set() # Green light, set flag bit count = 0 else: print("\33[42;1mgreen light is on...\033[0m") time.sleep(1) count += 1 def car(name): while True: if event.is_set(): #Determine whether flag bit is set print("[%s] running..."%name) time.sleep(1) else: print("[%s] sees red light,waiting..."%name) event.wait() print("[%s] green light is on,start going..."%name) light = threading.Thread(target=lighter,) light.start() car = threading.Thread(target=car,args=("MINI",)) car.start()