Last Friday's homework - multi-process to achieve TCP server concurrency
# Server import socket from multiprocessing import Process def get_server(): server = socket.socket() server.bind(('127.0.0.1', 9999)) server.listen(5) return server # Pass the socket object with encapsulated properties to other functions def get_talk(sock): while True: data = sock.recv(1024) print(data.decode('utf8')) sock.send(data.upper()) if __name__ == '__main__': server = get_server() # Get the socket object while True: sock, addr = server.accept() # Establish a channel and get the client address # Open multiple processes to chat p = Process(target=get_talk, args=(sock,)) p.start() _______________________________ # There is no difference in the client, just write the normal version in the same way
1. Mutual exclusion lock - Lock, mutex
Change concurrency and parallelism into serial, sacrificing efficiency but improving data security
from multiprocessing import Process,Lock lock making mutex = Lock() with a lock mutex.acquire() # To grab a lock, it must be placed in the operation data layer mutex.release() # put the lock
2. Thread theory
Process - resource unit
Thread - Execution Unit
There is at least one thread inside a process! ! !
The process is to open up memory space, and the thread is executed on the process without occupying the memory space, so the resource occupation of creating a process is much larger than that of creating a process
from threading import Thread import time def a(name): time.sleep(0.01) # Because the thread execution is fast, try adding a block print(f'{name} running') time.sleep(3) print(f'{name} Finished') if __name__ == '__main__': t = Thread(target=a, args=('jack',)) t.start() print('The main thread executes') >>> The main thread executes jack running jack Finished
Three, many methods of thread
1.join method
same as process
2. Multiple thread data sharing under the same process
Because there are not multiple copy memory spaces, it is shared data
3. Thread name
Similar to the process ID, current_thread
4. Thread process number
Multiple threads under the same process have a process number
5. Count the number of threads under the same process
activeCount
Note that if you do not manually add blocking, use the for loop to generate multiple threads, and each cycle generates a thread that is executed and disappears
6. Daemon thread
same as daemon
7. Mutex lock
There is also a Lock submodule, the usage is the same
Four, GIL global interpreter lock - only in CPython
1 Introduction
1. There is a global interpreter lock (GIL) in the CPython interpreter
There are many types of python interpreters
CPython JPython PyPython (commonly used is the CPython interpreter)
2.GIL is essentially a mutex used to prevent multiple threads in the same process from executing at the same time (important)
3.GIL exists because memory management in the CPython interpreter is not thread-safe (garbage collection mechanism)
2. How to bypass the GIL
from threading import Thread import time num = 1 def a(): global num c = num time.sleep(0.5) # In fact, this is similar to grabbing tickets, because it is multi-threaded, let the threads sleep for a while, and re-created a variable name, forcibly avoiding the GIL lock num = c + 1 t_list = [] for i in range(1, 100): t = Thread(target=a) t.start() t_list.append(t) for t in t_list: # Make sure all processes are running to completion t.join() print(num) >>> 2 # If you do not change the variable name in a, the GIL lock will be affected, and the result is 100
GIL can only ensure that multi-threaded data in the same process will not be messed up by the garbage collection mechanism, and cannot ensure the safety of data in the program
Verify that python multithreading is useful
According to the situation
1.cpu situation
single cpu
Multiple CPUs
2. Code situation
io-intensive (the code has io operations)
Computationally intensive (the code has no io)
3. Single cpu
- io-intensive
1. Multi-process
Total time consumption (time consumption of a single process + io + application space + copy code)
2. Multithreading
Total time consumption (time consumption of a single process plus +io)
! ! ! Advantages of multithreading
- Computationally intensive
1. Multi-process
Applying for additional space consumes more resources (total time-consuming + application space + copy code + switching)
2. Multithreading
Relatively less time-consuming resources Through multi-channel technology (total time-consuming + switching)
! ! ! Advantages of multithreading
4. Multiple CPUs
- io-intensive
1. Multi-process
Total time consumption (time consumption of a single process + io + application space + copy code)
2. Multithreading
Total time consumption (single process time consumption + io)
! ! ! Advantages of multithreading
- Computationally intensive
1. Multi-process
Total time consumption (time consumption of a single process)
2. Multithreading
Total time-consuming (combination of multiple processes)
! ! ! Multi-process wins!
Five, semaphore
In python concurrent programming, semaphores are equivalent to multiple mutex locks (for example, public toilets)
In other knowledge, it means that reaching a certain condition automatically triggers other operations
from threading import Thread, Lock, Semaphore import time import random sp = Semaphore(5) # Generate five locks at once class MyThread(Thread): def run(self): sp.acquire() print(self.name) time.sleep(random.randint(1, 3)) sp.release() for i in range(20): t = MyThread() t.start() # It is equivalent to asking 20 people to squeeze the toilet. There are only five toilets, and new people can go in and use any one of them.
Six, event event - you can suspend the thread or process
from threading import Thread, Event import time event = Event() # Create an event object def light(): print('Red street light with red light on, waiting for green light>>>') time.sleep(1) print('3') time.sleep(1) print('2') time.sleep(1) print('1') time.sleep(1) print('The green light is on! Games start!') event.set() # Let the awaited object execute immediately def car(name): print(f'{name} Waiting at the traffic light at the starting line') event.wait() # Make processes spawned from this function wait print(f'Games start! {name}sprint! ') t = Thread(target=light) t.start() # The following code is executed during the sleep period of the process generated by this function, and the process is generated immediately for i in range(1, 10): t = Thread(target=car, args=(f'Marshmallow SR{i}',)) t.start() >>> Red street light with red light on, waiting for green light>>> Marshmallow SR1 Waiting at the traffic light at the starting line Marshmallow SR2 Waiting at the traffic light at the starting line Marshmallow SR3 Waiting at the traffic light at the starting line Marshmallow SR4 Waiting at the traffic light at the starting line Marshmallow SR5 Waiting at the traffic light at the starting line Marshmallow SR6 Waiting at the traffic light at the starting line Marshmallow SR7 Waiting at the traffic light at the starting line Marshmallow SR8 Waiting at the traffic light at the starting line Marshmallow SR9 Waiting at the traffic light at the starting line 3 2 1 The green light is on! Games start! Games start! Marshmallow SR4 sprint! Games start! Marshmallow SR5 sprint! Games start! Marshmallow SR2 sprint! Games start! Marshmallow SR1 sprint! Games start! Marshmallow SR8 sprint! Games start! Marshmallow SR6 sprint! Games start! Marshmallow SR3 sprint! Games start! Marshmallow SR7 sprint! Games start! Marshmallow SR9 sprint!
Seven, process pool, thread pool
The maximum number of processes and threads can be set in advance, which can prevent the computer from being stuck due to too many processes or threads
Of course, because of the restrictions, the execution efficiency of the program is reduced
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor import time # 1 yields a fixed number of threads p = ProcessPoolExecutor(12) # pool = ThreadPoolExecutor(10) def test(name): print(f'Test is running Tester{name}>>>') time.sleep(2) print(f'Test Execution Completed Tester{name}>>>') return 'job done' def func(a): print('I will be responsible for collecting the results') print(a.result()) # To print the return value, use result() if __name__ == '__main__': # Process don't forget main for i in range(1, 24): # Directly stuff tasks into the pool, and the pool creates processes in batches according to the set number p.submit(test, 'jack').add_done_callback(func) # Get the result of the process execution by calling the function that specifically receives the result
Eight, coroutine - gevent third-party module
Because the CPU is the core of the work, and if an io operation is encountered during program execution, the CPU will leave temporarily. The coroutine technology can deceive the CPU to pretend that there is no io operation in the code, allowing the CPU to follow along all the time to achieve maximum efficiency. Purpose.
This module does not need to understand the underlying principles. This is a method packaged by other big guys, so you can use it
from gevent import monkey; monkey.patch_all() # Fixed syntax for detecting all IO operations (monkey patch) from gevent import spawn import time def a(): print('a running') time.sleep(2) print('a end of execution') def b(): print('b running') time.sleep(3) print('b end of execution') if __name__ == '__main__': start_time = time.time() a() b() print(time.time() - start_time)# >>> 5.056353569030762 ---------------------------- if __name__ == '__main__': start_time = time.time() s1 = spawn(a) s2 = spawn(b) s1.join() s2.join() print(time.time() - start_time) # >>>3.0264976024627686
Nine, single thread to achieve high concurrency
# Server from gevent import monkey; monkey.patch_all() from gevent import spawn import socket def a(sock): while True: date = sock.recv(1024) print(date.decode('utf8')) sock.send(date.upper()) def s(): sever = socket.socket() sever.bind(('127.0.0.1', 8088)) sever.listen(5) while True: sock, addr = sever.accept() spawn(a, sock) s1 = spawn(s) s1.join() -------------------------- # client import socket c1 = socket.socket() c1.connect(('127.0.0.1', 8088)) while True: c1.send(b'hello world') date = c1.recv(1024) print(date.decode('utf8')) # Remember to open the repeated execution of a single Py file in pycharm
↑↑↑↑↑↑↑↑