python multithreading
1. The concept of thread
Thread is the basic unit of CPU resource allocation. When a program starts running, the program becomes a process, and a process is equivalent to one or more threads. When there is no multi-threaded programming, a process is equivalent to a main thread; when multi-threaded programming, a process contains multiple threads (including the main thread). The use of threads can achieve large program development.

Multiple threads can run in the same program, and each thread performs a different task.

Multithreading realizes that the background service program can handle multiple tasks at the same time without blocking.

The characteristic of multi-threaded programming is that it can improve program execution efficiency and processing speed. A python program can run multiple relatively independent threads in parallel at the same time.

2. Create multithreading
Python supports two ways to create multithreading:

~Created by threading.Thread().

~By inheriting from the threading.Thread class.

1. Created by threading.Thread ()
Grammatical form:

thread.Thread(group=Nore, target=None, args=(), kwargs={},*, daemon=None)
1
Parameter explanation:

~group: must be None, related to the ThreadGroup class, generally not used.

~target: The object called by the thread is the target function.

~name: Give this name to the thread. The default is Tread-x, x is the serial number, starting from 1, the name of the first created thread is Tread-1.

~args: Pass keyword arguments for the target function, a dictionary.

~daemon: Used to set whether the thread exits with the main thread exiting.

Example:

import threading
def test(x,y):
for i in range(x,y):
print(i)
thread1 = threading.Thread(name=’t1′, target= test, args=(1,10))
thread2 = threading.Thread(name=’t2′, target= test, args=(11,20))
thread1.start() #start thread 1
thread2.start() #start thread 2
1
2
3
4
5
6
7
8
output:
1
2
3
4
5
6
7
8
9
11
12
13
14
15
16
17
18
19

Explanation: The two programs will run concurrently, so the result is not necessarily in the order of 1~10 every time, which is determined according to the time segment allocated by the CPU to the two threads. You can see that the results are different each time.

2. By inheriting the threading.Thread class inheritance
threading.Thread is a class, you can inherit it.

Example:

import threading
class mythread(threading.Thread):
def run(self):
for i in range(1,10):
print(i)
thread1 = mythread();
thread2 = mythread();
thread1.start()
thread2.start()

output:

1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9

Explanation: Customize a class to inherit threading.Thread, and then rewrite the run method of the parent class, which will be automatically executed when the thread starts (execute start()).

Three, the main thread
In python, the main thread is the first thread started.

~Parent thread: If a thread B is started in the startup thread A, A is the parent thread of B.

~Sub-thread: B is the sub-thread of A.

There is a damon attribute when creating a thread, which is used to judge the main thread. When the daemon is set to False, the thread will not exit with the main thread, and the main thread will wait for the child thread to finish executing;. When the daemon is set to True, the thread will exit with the main thread exiting, and the other sub-threads will be forced to exit after the main thread ends.

Note on using daemon:

The ~daemon attribute must be set before start(), otherwise a RuntimeError exception will be raised

~Each thread has a daemon attribute, which can be displayed or not set. If not set, the default value is None

~If the sub-sub-thread does not set the daemon attribute, take the daemon of the current thread to set it. The sub-thread inherits the daemon value of the sub-thread, and the effect is the same as setting None.

~ All threads created from the main thread do not set the daemon attribute, and the default is daemon=False.

Example:
import time
import threading
def test():
time.sleep(10)
for i in range(10):
print(i)
thread1 = threading.Thread(target=test,daemon=False)
thread1.start()
print(‘主线程完成了’)

output:

主线程完成了
0
1
2
3
4
5
6
7
8
9

Explanation: After the main thread finishes running and outputting, wait for a while and then output 0~9. If daemon=False is changed to daemon=True, the for i in range(10) statement will not be run.

4. Blocking threads
When one thread calls the join method of another thread, the caller is blocked until the calling thread is terminated.

Grammatical form:

1|join(timeout-=None)

The timeout parameter specifies how long the caller waits. If it is not set, it will wait for the called thread to end and the called thread to end. Among them, a thread can be called join multiple times.

Example:

import time
import threading
def test():
time.sleep(5)
for i in range(10):
print(i)
thread1=threading.Thread(target=test)
thread1.start()
thread1.join()
print(‘主线程完成了’)

output:

0
1
2
3
4
5
6
7
8
9
主线程完成了

Explanation: Add thread1.join() after thread1.start() to add the join method. When outputting, the main thread will wait for the output of 0~9 before executing its own print output.

5. Determine whether the thread is active
~run(): method used to represent thread activity

~start(): start the thread

~join(): wait until the thread terminates

~isAlive(): Returns whether the thread is alive

~getName(): returns the thread name

~setName() : set thread name

Example:
from threading import Thread, Event
import time
def countdown(n, started_evt):
print(‘正在运行’)
started_evt.set()
while n > 0:
print(‘时间’, n)
n -= 1
time.sleep(2)
started_evt = Event()
print(‘开始倒计时’)
t = Thread(target=countdown, args=(10, started_evt))
t.start()
started_evt.wait()
print(‘倒计时运行’)

output:

开始倒计时
正在运行
时间 10
倒计时运行
时间 9
时间 8
时间 7
时间 6
时间 5
时间 4
时间 3
时间 2
时间 1

Alive, as the name suggests, indicates whether the thread is currently available. If the thread has been started and there are no exceptions, it returns true, otherwise it is false.

Thread.isAlive() : As the name implies, it indicates that the current thread is in an available state, that is, whether it is already started and running;

6. Thread synchronization
1. Synchronization concept
In the case of asynchronous mode, one thread is modifying the shared data at the same time, and another thread is reading the shared data. When the thread that modifies the shared data has not finished processing, the thread that reads the data will definitely get the wrong result. If a multi-thread synchronization control mechanism is adopted, after the thread processing the shared data finishes processing the data, the reading thread reads the data.

Python’s lock solves this problem, locks the thread, only allows one thread to operate, and other threads wait in line. After the current thread completes the operation, it will run one by one in order.

2. Python lock
Python’s threading module provides a solution to RLock locks. At a certain time, only one thread operation statement can be placed between the acquire method and release method of RLock, that is, acquire is equivalent to locking RLack, and release is equivalent to unlocking.

Example:
import threading
class mythread(threading. Thread):
def run(self):
global x #declare a global variable
lock.acquire() #lock
x +=10
print(‘%s:%d’%(self.name,x))
lock.release() #unlock
x = 0 #Set global variable initial value
lock = threading.RLock() #Create a reentrant lock
list1 = []
for i in range(5):
list1.append(mythread()) #Create five threads and put them in the same list
for i in list1:
i.start() #Start list thread

output:

Thread-1:10
Thread-2:20
Thread-3:30
Thread-4:40
Thread-5:50

Explanation:

3. Conditional lock in python
Commonly used methods for conditional locks:

~acquire([timeout]): method to invoke the associated lock

~release(): unlock

~wait(): Make the thread enter the waiting pool of the Condition to wait for the notification and release the unlock. The thread must have acquired the lock before using it, otherwise an exception will be thrown.

~notify(): Select a thread from the waiting pool and notify it. The thread that receives the notification will automatically call acquire() to try to obtain it. Other threads are still waiting for the notification in the waiting pool until the thread receives the notification and calls this method, otherwise it will will throw an exception.

~notify ALL(): Same as notify(), but this method corresponds to all threads.

Example:

Topic: There are several production workshops producing, and several consumers buying. When the production reaches a certain amount, stop production.
import threading
import time
condtion = threading.Condition()
sheep = [‘1件产品’,’1件产品’,’1件产品’,’1件产品’,’1件产品’]
class Producer(threading.Thread):
def __init__(self, name):
super().__init__(name=name)
pass
def run(self):
global condtion, sheep
while True:
time.sleep(0.1)
condtion.acquire()
if len(sheep) < 10:
print(self.name + “生产了1件产品”)
sheep.append(‘1件产品’)
condtion.notifyAll()
pass
else:
print(“仓库满了,停止生产!”)
condtion.wait()
pass
condtion.release()
pass
pass
class Customer(threading.Thread):
def __init__(self, name):
super().__init__(name=name)
pass
def run(self):
global condtion, sheep
while True:
time.sleep(0.1)
condtion.acquire()
if len(sheep) > 0:
meat = sheep.pop()
print(self.name + “购买了” + meat + “还剩多少” + str(len(sheep)) + “件”)
condtion.notifyAll()
pass
else:
print(“买光了,等待”)
condtion.wait()
pass
condtion.release()
pass
pass
if __name__ == “__main__”:
p1 = Producer(“1号生产车间”)
p2 = Producer(“2号生产车间”)
p3 = Producer(“3号生产车间”)
p4 = Producer(“4号生产车间”)
p5 = Producer(“5号生产车间”)
p6 = Producer(“6号生产车间”)
p1.start()
p2.start()
p4.start()
p5.start()
p6.start()
c1 = Customer(‘小王’)
c2 = Customer(‘小李’)
c3 = Customer(‘小贾’)
c4 = Customer(‘小沈’)
c5 = Customer(‘小刘’)
c1.start()
c2.start()
c3.start()
c4.start()
c5.start()

By hmimcu