Threads are similar to executing multiple different programs at the same time , Multithreading has the following advantages :
Each independent thread has an entry for the program to run 、 Exit of sequential execution sequence and program . But threads can't execute independently , Must exist in the application , Multiple thread execution control provided by the application .
Each thread has its own set CPU register , Called the context of the thread , This context reflects the CPU The state of the register .
Instruction pointer and stack pointer registers are the two most important registers in the thread context , Threads always run in the context of the process getting , These addresses are used to mark the memory in the address space of the process that owns the thread .
Threads can be divided into :
Python3 The two modules commonly used in threads are :
thread The module has been discarded . Users can use threading Module instead of . therefore , stay Python3 We can't use "thread" modular . For compatibility ,Python3 take thread Rename it to "_thread".
Python There are two ways to use threads in : Function or use class to wrap thread object .
Functional expression : call _thread Module start_new_thread() Function to generate a new thread . The grammar is as follows :
_thread.start_new_thread ( function, args[, kwargs] )
Parameter description :
#!/usr/bin/python3
import _thread
import time
# Define a function for the thread
def print_time( threadName, delay):
count = 0
while count < 5:
time.sleep(delay)
count += 1
print ("%s: %s" % ( threadName, time.ctime(time.time()) ))
# Create two threads
try:
_thread.start_new_thread( print_time, ("Thread-1", 2, ) )
_thread.start_new_thread( print_time, ("Thread-2", 4, ) )
except:
print ("Error: Unable to start thread ")
while 1:
pass
The output of the above program is as follows :
Thread-1: Wed Jan 5 17:38:08 2022
Thread-2: Wed Jan 5 17:38:10 2022
Thread-1: Wed Jan 5 17:38:10 2022
Thread-1: Wed Jan 5 17:38:12 2022
Thread-2: Wed Jan 5 17:38:14 2022
Thread-1: Wed Jan 5 17:38:14 2022
Thread-1: Wed Jan 5 17:38:16 2022
Thread-2: Wed Jan 5 17:38:18 2022
Thread-2: Wed Jan 5 17:38:22 2022
Thread-2: Wed Jan 5 17:38:26 2022
You can press the ctrl-c sign out .
Python3 Through two standard libraries _thread and threading Provides support for threads .
_thread Provides a low level of 、 The original thread and a simple lock , It's compared to threading The function of the module is limited .
threading The module contains _thread Out of all methods in the module , Other methods are also provided :
In addition to the method of use , The thread module also provides Thread Class to handle threads ,Thread Class provides the following methods :
We can do this by directly from threading.Thread Inheritance creates a new subclass , After instantiation, it is called start() Method to start a new thread , That is, it calls the thread's run() Method :
#!/usr/bin/python3
import threading
import time
exitFlag = 0
class myThread (threading.Thread):
def __init__(self, threadID, name, delay):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.delay = delay
def run(self):
print (" Start thread :" + self.name)
print_time(self.name, self.delay, 5)
print (" Exit thread :" + self.name)
def print_time(threadName, delay, counter):
while counter:
if exitFlag:
threadName.exit()
time.sleep(delay)
print ("%s: %s" % (threadName, time.ctime(time.time())))
counter -= 1
# Create a new thread
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# Start a new thread
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print (" Exit main thread ")
The results of the above procedures are as follows ;
Start thread :Thread-1 Start thread :Thread-2 Thread-1: Wed Jan 5 17:34:54 2022 Thread-2: Wed Jan 5 17:34:55 2022 Thread-1: Wed Jan 5 17:34:55 2022 Thread-1: Wed Jan 5 17:34:56 2022 Thread-2: Wed Jan 5 17:34:57 2022 Thread-1: Wed Jan 5 17:34:57 2022 Thread-1: Wed Jan 5 17:34:58 2022 Exit thread :Thread-1 Thread-2: Wed Jan 5 17:34:59 2022 Thread-2: Wed Jan 5 17:35:01 2022 Thread-2: Wed Jan 5 17:35:03 2022 Exit thread :Thread-2 Exit main thread
If multiple threads modify a data together , Then unexpected results may occur , In order to ensure the correctness of the data , Multiple threads need to be synchronized .
Use Thread Object's Lock and Rlock It can realize simple thread synchronization , Both of these objects have acquire Methods and release Method , For data that requires only one thread at a time , It can be operated in acquire and release Between methods . as follows :
The advantage of multithreading is that it can run multiple tasks at the same time ( At least it feels like this ). But when threads need to share data , There may be data out of sync .
Consider a situation like this : All the elements in a list are 0, Threads "set" Change all elements from back to front to 1, And threads "print" Responsible for reading the list from front to back and printing .
that , Maybe threads "set" At the beginning of the change , Threads "print" So I'm going to print the list , The output is half 0 Half 1, This is the data out of sync . To avoid that , The concept of lock is introduced .
There are two states of lock —— Locked and unlocked . Every time a thread such as "set" To access shared data , Lock must be obtained first ; If there are other threads such as "print" Get locked , So let the thread "set" Pause , That's synchronous blocking ; Wait until the thread "print" Access to complete , After releasing the lock , Let the thread "set" continue .
After such treatment , When printing a list, you can either print it all 0, Or output it all 1, No more half 0 Half 1 The embarrassment of .
#!/usr/bin/python3
import threading
import time
class myThread (threading.Thread):
def __init__(self, threadID, name, delay):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.delay = delay
def run(self):
print (" Open thread : " + self.name)
# Get the lock , For thread synchronization
threadLock.acquire()
print_time(self.name, self.delay, 3)
# Release the lock , Start the 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 finish
for t in threads:
t.join()
print (" Exit main thread ")
Execute the above procedure , The output is :
Open thread : Thread-1 Open thread : Thread-2 Thread-1: Wed Jan 5 17:36:50 2022 Thread-1: Wed Jan 5 17:36:51 2022 Thread-1: Wed Jan 5 17:36:52 2022 Thread-2: Wed Jan 5 17:36:54 2022 Thread-2: Wed Jan 5 17:36:56 2022 Thread-2: Wed Jan 5 17:36:58 2022 Exit main thread
Python Of Queue Synchronous... Is provided in the module 、 Thread safe queue class , Include FIFO( First in, first out ) queue Queue,LIFO( After the first out ) queue LifoQueue, And priority queues PriorityQueue.
These queues all implement lock primitives , Can be used directly in multithreading , You can use queues to synchronize threads .
Queue Common methods in modules :
#!/usr/bin/python3
import queue
import threading
import time
exitFlag = 0
class myThread (threading.Thread):
def __init__(self, threadID, name, q):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.q = q
def run(self):
print (" Open thread :" + self.name)
process_data(self.name, self.q)
print (" Exit thread :" + self.name)
def process_data(threadName, q):
while not exitFlag:
queueLock.acquire()
if not workQueue.empty():
data = q.get()
queueLock.release()
print ("%s processing %s" % (threadName, data))
else:
queueLock.release()
time.sleep(1)
threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
queueLock = threading.Lock()
workQueue = queue.Queue(10)
threads = []
threadID = 1
# Create a new thread
for tName in threadList:
thread = myThread(threadID, tName, workQueue)
thread.start()
threads.append(thread)
threadID += 1
# Fill the queue
queueLock.acquire()
for word in nameList:
workQueue.put(word)
queueLock.release()
# Wait for the queue to clear
while not workQueue.empty():
pass
# Notify the thread that it's time to exit
exitFlag = 1
# Wait for all threads to finish
for t in threads:
t.join()
print (" Exit main thread ")
The results of the above procedures :
Open thread :Thread-1 Open thread :Thread-2 Open thread :Thread-3 Thread-3 processing One Thread-1 processing Two Thread-2 processing Three Thread-3 processing Four Thread-1 processing Five Exit thread :Thread-3 Exit thread :Thread-2 Exit thread :Thread-1 Exit main thread