Chapter 42 of the official Python column, students stop. Don't miss this article starting from 0!
Earlier, the school committee shared several articles on multithreading. When it comes to the synchronization mechanism, it seems quite simple. Just add a lock.
This time, let's take a look at a real scene: bank transfer
Let's talk about transfer first
Suppose there is a xuewei account with 100W in it.
Then there are multiple tasks in transfer, and transfer in and transfer out are related to this xuewei account.
And these tasks happen randomly.
Let's write the above scenario into code:
xuewei_account = 100 # If amount is negative, it is the transfer out amount def transfer(money): global xuewei_account xuewei_account += money
The following are multiple threads. Multiple threads simulate transfer events. We assume that four events occur at the same time.
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time: 12:02 am, November 24, 2021 # @Author : LeiXueWei # @CSDN/Juejin/Wechat: Thunder Science Committee # @XueWeiTag: CodingDemo # @File : __init__.py.py # @Project : hello import random import threading import datetime import time xuewei_account = 100 # If amount is negative, it is the transfer out amount def transfer(money): global xuewei_account xuewei_account += money # Create 4 tasks to transfer to the school committee account for i in range(10000): threading.Thread(target=lambda: transfer(-1)).start() threading.Thread(target=lambda: transfer(1)).start() threading.Thread(target=lambda: transfer(-1)).start() threading.Thread(target=lambda: transfer(1)).start() # Only the main thread MainThread is left waiting for the active thread time.sleep(10) print("-" * 16) print("Number of active threads:", threading.active_count()) print("Active thread:", threading.current_thread().name) print("School Committee account balance:", xuewei_account)
Here, four threads were started and cycled for 10000 times, that is, 40000 threads, which were transferred to the account of the school committee.
Here are the results:
After several times of operation, the account of the school committee is still correct, and the balance is still 100W.
The above code has tens of thousands of threads, but each operation is very simple, completing an addition.
Threads start one by one and switch to the next thread very quickly. We see that there is no problem with the program.
Let's make a transformation. This time, we don't need 40000 threads. We make the task of transfer more time-consuming. Each thread is started to simulate 100000 transfers.
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time: 12:02 am, November 24, 2021 # @Author : LeiXueWei # @CSDN/Juejin/Wechat: Thunder Science Committee # @XueWeiTag: CodingDemo # @File : __init__.py.py # @Project : hello import random import threading import datetime import time xuewei_account = 100 # If amount is negative, it is the transfer out amount def transfer(money): global xuewei_account for x in range(100000): xuewei_account += money # Create 4 tasks to transfer to the account of the repeated School Committee for i in range(10): threading.Thread(target=lambda: transfer(-1)).start() threading.Thread(target=lambda: transfer(1)).start() threading.Thread(target=lambda: transfer(-1)).start() threading.Thread(target=lambda: transfer(1)).start() time.sleep(10) print("-" * 16) print("Number of active threads:", threading.active_count()) print("Active thread:", threading.current_thread().name) print("School Committee account balance:", xuewei_account)
The results of the operation here are quite unexpected:
The complexity of multithreaded programming is here. Sometimes plain code is transformed into multithreading, which is easy to bug!
Of course, the above code is not ordinary. Compared with the first code, the above transfer function does more events and takes more time.
How to solve this problem?
It's very simple. Let's lock it.
The code is as follows:
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time: 12:02 am, November 24, 2021 # @Author : LeiXueWei # @CSDN/Juejin/Wechat: Thunder Science Committee # @XueWeiTag: CodingDemo # @File : __init__.py.py # @Project : hello import random import threading import datetime import time xuewei_account = 100 lock = threading.Lock() # If amount is negative, it is the transfer out amount def transfer(money): lock.acquire() global xuewei_account for x in range(100000): xuewei_account += money lock.release() # Create 4 tasks to transfer to the account of the repeated School Committee for i in range(10): threading.Thread(target=lambda: transfer(-1)).start() threading.Thread(target=lambda: transfer(1)).start() threading.Thread(target=lambda: transfer(-1)).start() threading.Thread(target=lambda: transfer(1)).start() time.sleep(10) print("-" * 16) print("Number of active threads:", threading.active_count()) print("Active thread:", threading.current_thread().name) print("School Committee account balance:", xuewei_account)
The operation results are as follows:
No matter how the above code runs and how many times it runs, the final account of the school committee is 100 (PS: the school committee will not contact the readers to transfer money. This should be paid special attention).
No matter how many threads there are, the code for internal transfer of each transfer function (from global to + = money) will only be called by one thread.
summary
Based on this article and the previous article, we show the idea of synchronization mechanism to solve some programming problems. Readers can learn more and think about the application of locks.
Why is there an error in the calculation when the amount is heavily operated (the second code in this article)!
Here, amount is equivalent to variables operated by multiple threads, that is, shared variables. In multi-threaded programming, special attention should be paid to such variables to avoid the operation of shared variables. Some programs have no problems when the concurrency scale is very small.
Concurrent programming is a programming method that makes high use of CPU computing power. Concurrent programs are programs that perform similar tasks in parallel. This can be compared with single threaded applications.
But I don't know that unexpected output will appear when a certain piece of code is called in 100000 million a second.
This is the meaning of learning multithreaded programming. It is also a barrier for programmers. They must overcome it!
Today's share is here. The next article will continue to share the lock free solution to the shared variable problem.
By the way, if you like Python, please pay attention to the school committee Python foundation column or Introduction to Python to master the big column
Continuous learning and continuous development, I'm Lei Xuewei!
Programming is very interesting. The key is to understand the technology thoroughly.
Welcome to wechat, like and support collection!