Python has built-in threading module, which encapsulates the lower level thread module
for built-in methods, see the official document: threading – thread based parallelism
Multithreading execution
The main thread will wait for all the child threads to finish
#coding=utf-8
import threading
import time
def thread_test():
print("test.")
time.sleep(1)
if __name__ == "__main__":
for i in range(5):
t = threading.Thread(target=thread_test)
t.start()
View the number of threads
#coding=utf-8
import threading
from time import sleep, ctime
def a():
for i in range(3):
print("a...%d"%i)
sleep(1)
def bbbbb():
for i in range(3):
print("bbbbb...%d"%i)
sleep(1)
if __name__ == '__main__':
print('---start---:%s'%ctime())
t1 = threading.Thread(target=a)
t2 = threading.Thread(target=bbbbb)
t1.start()
t2.start()
while True:
length = len(threading.enumerate())
# length = threading.active_count()
print('The number of threads currently running is: %d'%length)
if length<=1:
break
sleep(0.5)
Encapsulating the threading. Thread class
Inherit threading. Thread and override run method
#coding=utf-8
import threading
import time
class MyThread(threading.Thread):
def run(self):
for i in range(3):
time.sleep(1)
msg = "I'm "+self.name+' @ '+str(i) The name of the current thread is stored in the #name attribute
print(msg)
if __name__ == '__main__':
t = MyThread()
t.start()
Thread execution order
Each thread runs a complete run function, but the start order of the thread and the execution order of each loop in the run function cannot be determined.
Sharing global variables and passing parameters
# Shared global variables
from threading import Thread
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)
print("---Before the thread is created g_num is %d---"%g_num)
t1 = Thread(target=work1)
t1.start()
#Delay for a while to make sure things are done in thread t1
time.sleep(1)
t2 = Thread(target=work2)
t2.start()
All threads in a process share global variables, which is very convenient to share data among multiple threads. Disadvantages: threads change global variables randomly, which may cause confusion among multiple threads (that is, threads are not safe)
from threading import Thread
import time
def work1(nums):
nums.append(44)
print("----in work1---",nums)
def work2(nums):
#Delay for a while to make sure things are done in thread t1
time.sleep(1)
print("----in work2---",nums)
g_nums = [11,22,33]
t1 = Thread(target=work1, args=(g_nums,))
t1.start()
t2 = Thread(target=work2, args=(g_nums,))
t2.start()
Mutex
When multiple threads modify a shared data almost at the same time, synchronization control is needed.
when a thread wants to change the shared data, lock it first. At this time, the resource status is “locked”, and other threads cannot change it; Until the thread releases the resource and changes its state to “non locked”, other threads can lock the resource again. Mutex ensures that only one thread can write each time, so as to ensure the correctness of data in the case of multithreading.
Advantages ensure that a piece of key code can only be completely executed by one thread from beginning to end. Disadvantages 1 prevent the concurrent execution of multiple threads. In fact, a piece of code containing locks can only be executed in single thread mode, which greatly reduces the efficiency. Disadvantages 2 because there can be multiple locks, different threads hold different locks, and try to obtain the lock held by the other party, Deadlock may occur
import threading
import time
g_num = 0
def test1(num):
global g_num
for i in range(num):
mutex.acquire()
g_num += 1
mutex.release()
print("---test1---g_num=%d"%g_num)
def test2(num):
global g_num
for i in range(num):
mutex.acquire()
g_num += 1
mutex.release()
print("---test2---g_num=%d"%g_num)
# Create a mutually exclusive lock
# Default is the unlocked state
mutex = threading.Lock()
# Create 2 threads and have them each add 1000000 times to g_num
p1 = threading.Thread(target=test1, args=(1000000,))
p1.start()
p2 = threading.Thread(target=test2, args=(1000000,))
p2.start()
# Wait for the calculation to complete
while len(threading.enumerate()) ! = 1:
time.sleep(1)
print("The final result after 2 threads operate on the same global variable is:%s" % g_num)
Mutex can use context manager
to use lock, condition and semaphore in with statement
the object with acquire() and release() method provided by this module can be used as context manager of with statement. When entering a statement block, the acquire () method will be called, and when exiting a statement block, release () will be called. Therefore, the following fragments:
with some_lock:
# do something...
# Equivalent to :
some_lock.acquire()
try:
# do something...
finally:
some_lock.release()
Lock, RLOCK, condition, semaphore, and boundedsemaphore objects can now be used as context managers for the with statement.
Multithreading case [chat]
Write a program with two threads
thread 1 is used to receive data and then display
thread 2 is used to detect keyboard data and then send data through UDP
import socket
import threading
def send_msg(udp_socket):
"""Get the keyboard data and send it to the other side """
while True:
# 1. input data from keyboard
msg = input("\nPlease enter the data to be sent:")
# 2. enter the ip address of the other party
dest_ip = input("\nPlease enter the other party's ip address:")
# 3. enter the other party's port
dest_port = int(input("\nPlease enter the other party's port:"))
# 4. send data
udp_socket.sendto(msg.encode("utf-8"), (dest_ip, dest_port))
def recv_msg(udp_socket):
"""Receive data and display """
while True:
# 1. receive data
recv_msg = udp_socket.recvfrom(1024)
# 2. decode
recv_ip = recv_msg[1]
recv_msg = recv_msg[0].decode("utf-8")
# 3. display the received data
print(">>>%s:%s" % (str(recv_ip), recv_msg))
def main():
# 1. Create a socket
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 2. bind local information
udp_socket.bind(("", 7890))
# 3. create a child thread to receive data
t = threading.Thread(target=recv_msg, args=(udp_socket,))
t.start()
# 4. let the main thread detect the keyboard data and send
send_msg(udp_socket)
if __name__ == "__main__":
main()