Multithreading
1. Process: producer-consumer model
A programming ideas, models, design patterns, theory, etc., are handed you a programming method, and later encountered a similar situation, you can apply
The three elements of the model of producers and consumers:
- Manufacturer: generating data
- Consumers: receiving data for further processing
- Container: buffer (queue) acts as a cushion to balance productivity with consumers, decoupling
2. Thread the theoretical knowledge
What is the thread
An assembly line workflow
Process: a process of open space in memory, and then copy all the resources of the primary process, and then call the cpu to execute the code.
Process is the basic unit of resource scheduling, and the thread is the smallest unit of execution of cpu
Open process: the process will open up a space in the memory process, the entire process of copying data to a main thread will execute the code inside
Thread vs Process
- Open process overhead is very large, much larger than the overhead of thread.
- Open thread speed is very fast, faster than the process several times to a hundred times.
- A process the same data can be shared between threads and threads, queues, etc. required by the process and method of communication between processes.
Threaded application
Concurrency: cpu looks like a simultaneous execution of multiple tasks
A single process to open three threads, concurrent tasks.
Open three processes concurrent tasks.
The advantages of open multi-threading: data sharing, small overhead, fast.
The main thread and the child thread no distinction between them
So who is in a process work?
A main thread in the work, when the main thread is finished executing code, have to wait for other threads executing the order to withdraw from the process.
3. Open thread in two ways
** thread does not need to if _ _ name _ _ == '_ _ main _ _': next statement **
The first:
from threading import Thread
import time
def task(name):
print(f"{name} is running")
time.sleep(1)
print(f"{name} is gone")
if __name__ == '__main__':
t1 = Thread(target=task,args=("zcy",))
t1.start()
print("==main Threading==") # 线程没有主次之分
The second:
from threading import Thread
import time
class MyThread(Thread):
def __init__(self,name,lst,s):
super(MyThread, self).__init__()
self.name = name
self.lst =lst
self.s = s
def run(self):
print(f"{self.name} is running")
time.sleep(1)
print(f"{self.name} is gone")
if __name__ == '__main__':
t1 = MyThread("zdr",[1,2,3],"180")
t1.start()
print("==main thread==")
4. Comparison of code thread vs process
Open speed comparison
# 多进程 from multiprocessing import Process def work(): print('hello') def task(): print('bye') if __name__ == '__main__': # 在主进程下开启线程 t1 = Process(target=work) t2 = Process(target=task) t1.start() t2.start() print('main thread/process')
# 多线程 from threading import Thread import time def task(name): print(f"{name} is running") time.sleep(1) print(f"{name} is gone") if __name__ == '__main__': t1 = Thread(target=task,args=("zdr",)) t2 = Thread(target=task,args=("zcy",)) t3 = Thread(target=task,args=("zfy",)) t4 = Thread(target=task,args=("lfz",)) t1.start() t2.start() t3.start() t4.start() print('==main thread==') # 线程是没有主次之分
Contrast pid
# 进程 from multiprocessing import Process import time import os def task(): print(f"子进程:{os.getpid()}") print(f"主进程:{os.getppid()}") if __name__ == '__main__': p1 = Process(target=task) p2 = Process(target=task) p1.start() p2.start() print(f"==main{os.getpid()}")
# 主线程 from threading import Thread import os def task(): print(os.getpid()) if __name__ == '__main__': t1 = Thread(target=task) t2 = Thread(target=task) t1.start() t2.start() print(f"===main thread:{os.getpid()}")
Threads share internal data within the same process
from threading import Thread import os x = 3 def task(): global x x = 100 if __name__ == '__main__': t1 = Thread(target=task) t1.start() print(f"===main thread:{x}") # 同一个进程内的资源数据对于这个进程的多个线程来说是共享的.
Small Exercise:
import multiprocessing
import threading
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind(('127.0.0.1',8080))
s.listen(5)
def action(conn):
while True:
data=conn.recv(1024)
print(data)
conn.send(data.upper())
if __name__ == '__main__':
while True:
conn,addr=s.accept()
p=threading.Thread(target=action,args=(conn,))
p.start()
多线程并发的socket服务端
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('127.0.0.1',8080))
while True:
msg=input('>>: ').strip()
if not msg:continue
s.send(msg.encode('utf-8'))
data=s.recv(1024)
print(data)
客户端
5. Other relevant thread
Thread object:
Thread .isAlive () # determine whether the thread is alive
Thread .getname () # Get the Thread name
Thread .setname () # set the thread name ***
Method of threading module:
threading.currentThread () # get the object of the current process
threading.enumerate () # returns a list of all the thread objects
threading.activeCount () # returns a number that indicates the number of threads still alive
from threading import Thread, currentThread, enumerate,activeCount
import os
import time
x = 3
def task():
# print(currentThread())
# time.sleep(1)
print("123")
if __name__ == '__main__':
t1 = Thread(target=task,name="xc-1")
t2 = Thread(target=task,name="xc-2")
# name 设置线程名
t1.start()
t2.start()
# time.sleep(2)
# print(t1.isAlive()) # 判断线程是否存活
# print(t1.getName()) # 获取线程名
# t1.setName("zcy-01")
# print(t1.name) # ***
# threading方法
# print(currentThread()) # 获取当前线程的对象
# print(currentThread().name) # 获取当前线程的对象
print(enumerate()) # 返回一个列表,包含所有的线程对象
print(activeCount())
print(f"===main thread:{os.getpid()}")
6.join and daemon threads
Then execute after blocking the main thread to inform the main thread to wait for the child thread is finished: join
# 线程join
from threading import Thread
import time
def task(name):
print(f"{name} is running")
time.sleep(1)
print(f'{name} is gone')
if __name__ == '__main__':
start_time = time.time()
t1 = Thread(target=task,args=("zdr",))
t2 = Thread(target=task,args=("zcy",))
t3 = Thread(target=task,args=("zfy",))
t1.start()
t1.join()
t2.start()
t2.join()
t3.start()
t3.join()
print(f"===main thread:{time.time() - start_time}")
Daemon thread:
Whether it is a process or thread, follow: Guardian xxx xxx will wait for the main run is finished after destruction
It is emphasized that: not finished running terminates
#1.对主进程来说,运行完毕指的是主进程代码运行完毕
#2.对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕
Detailed explanation:
#1 主进程在其代码结束后就已经算运行完毕了(守护进程在此时就被回收),然后主进程会一直等非守护的子进程都运行完毕后回收子进程的资源(否则会产生僵尸进程),才会结束,
#2 主线程在其他非守护线程运行完毕后才算运行完毕(守护线程在此时就被回收)。因为主线程的结束意味着进程的结束,进程整体的资源都将被回收,而进程必须保证非守护线程都运行完毕后才能结束。
To compare daemons:
from multiprocessing import Process
import time
def foo():
print(123)
time.sleep(1)
print("end123")
def bar():
print(456)
time.sleep(2)
print("end456")
if __name__ == '__main__':
p1 = Process(target=foo)
p2 = Process(target=bar)
p1.daemon = True
p1.start()
p2.start()
print('====main====')
Daemon thread:
from threading import Thread
import time
def sayhi(name):
print('bye~')
time.sleep(2)
print(f'{name} say hello ')
if __name__ == '__main__':
t = Thread(target=sayhi,args=('zcy',))
# t.setDaemon(True)
t.daemon = True
t.start()
print('主线程')
from threading import Thread
import time
def foo():
print(123) # 1
time.sleep(1)
print('end123') # 4
def bar():
print(456) # 2
time.sleep(3)
print('en456') # 3
t1 = Thread(target=foo)
t2 = Thread(target=bar)
t1.daemon = True
t1.start()
t2.start()
print('=====main====') # 3
结果:
123
456
=====main====
end123
en456
# 主线程什么时候结束?
# 主线程等待非守护子线程结束之后,结束
from threading import Thread
import time
def foo():
print(123) # 1
time.sleep(3)
print("end123")
def bar():
print(456) # 2
time.sleep(1)
print("end456") # 4
t1=Thread(target=foo)
t2=Thread(target=bar)
t1.daemon=True
t1.start()
t2.start()
print("main-------") # 3
结果:
123
456
main-------
end456
7. mutex
from threading import Thread
import time
import random
x = 100
def task():
time.sleep(random.randint(1,2))
global x
temp = x
time.sleep(random.randint(1,3))
temp = temp - 1
x = temp
if __name__ == '__main__':
l = []
for i in range(100):
t = Thread(target=task)
l.append(t)
t.start()
for i in l:
i.join()
print(f"main:{x}")
# 多个任务共抢一个数据,要保证数据的安全性,要让他们串行
# 给线程加锁
from threading import Thread
from threading import Lock
import time
import random
x = 100
def task(lock):
lock.acquire()
# time.sleep(random.randint(1,2))
global x
temp = x
time.sleep(0.01)
temp = temp - 1
x = temp
lock.release()
if __name__ == '__main__':
mutex = Lock()
l1 = []
for i in range(100):
t = Thread(target=task,args=(mutex,))
l1.append(t)
t.start()
time.sleep(3)
print(f'主线程{x}')