Chapter 46 of the official Python column, students stop. Don't miss this article starting from 0!
In the previous article, we accepted (learned) the Queue. This time, the learning committee will show how to use the Queue to solve the problem of transfer scenario.
Let's look at the transfer scenario again
The previous two articles show that the transfer repeatedly reads and writes the amount, resulting in an error in the result.
xuewei_account = dict() xuewei_account['amount'] = 100 # If amount is negative, it is the transfer out amount def transfer(money): for i in range(100000): xuewei_account['amount'] = xuewei_account['amount'] + money
In our previous articles, we used multiple threads to turn length repeatedly: + 1 and - 1.
Normally, the result should still be 100
This is all the code:
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time: 12:02 am, November 26, 2021 # @Author : LeiXueWei # @CSDN/Juejin/Wechat: Thunder Science Committee # @XueWeiTag: CodingDemo # @File : threadsafe_queue1.py # @Project : hello import random import threading import datetime import time xuewei_account = dict() xuewei_account['amount'] = 100 # If amount is negative, it is the transfer out amount def transfer(money): for i in range(100000): xuewei_account['amount'] = xuewei_account['amount'] + money # Create 20 tasks and transfer to the account of the school committee repeatedly threads = [] for i in range(10): t1 = threading.Thread(target=lambda: transfer(-1)) threads.append(t1) t2 = threading.Thread(target=lambda: transfer(1)) threads.append(t2) for t in threads: t.start() for t in threads: t.join() print("-" * 16) print("Number of active threads:", threading.active_count()) print("Active thread:", threading.current_thread().name) print("School Committee account balance:", xuewei_account)
Wait for all transfer threads to finish running, and we see that the result is wrong:
How to use queues to solve this problem?
As mentioned earlier, multithreading repeatedly reads and writes shared data is the root of the problem.
Change the code to synchronous mutual exclusion mode to ensure that one thread updates the shared data at any time, then the problem is solved. (as shown earlier, the Lock lock scheme is used)
How can I use this queue?
You can think for 10 seconds and think about how to do this according to the characteristics of locking and queue learned.
OK, the answer is now:
Queue this queue has multiple functions, one is the put function and the other is the get function.
One is responsible for putting data to the end of the queue, and the other can take elements from the opposite end.
It is just suitable for the transfer business. Can we turn each transfer operation into an instruction / event. For example:
event(amount=1,acount=xuewei_account) .... event(amount=-1,acount=xuewei_account) .... event(amount=1,acount=xuewei_account) .... event(amount=-1,acount=xuewei_account)
20 threads, each 100000 data reads and writes, a total of 2 million events.
So we can turn this into: 2 million transfer events.
Because the Queue is thread safe, we can transfer 2 million times concurrently and hand it over to another thread for transfer processing.
This ensures that only one thread is connected to Xuewei at a time_ The account of the academic committee can be read and written.
Transformation, using queues to solve problems
Display code:
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time: 12:02 am, November 26, 2021 # @Author : LeiXueWei # @CSDN/Juejin/Wechat: Thunder Science Committee # @XueWeiTag: CodingDemo # @File : threadsafe_queue2.py # @Project : hello import random import threading import datetime import time import queue q = queue.Queue() xuewei_account = dict() xuewei_account['amount'] = 100 # If amount is negative, it is the transfer out amount def transfer(money): for i in range(100000): q.put(money) def handle_amount(): while not q.empty(): amount = q.get() xuewei_account['amount'] += amount def monitor_q(): counter = 0 time.sleep(3) while counter < 1000 and not q.empty(): print("q size:", q.qsize()) time.sleep(3) counter+=1 q_thread = threading.Thread(name="Q monitor", target=monitor_q) q_thread.start() # Create 20 tasks and transfer to the account of the school committee repeatedly threads = [] for i in range(10): t1 = threading.Thread(target=lambda: transfer(-1)) threads.append(t1) t2 = threading.Thread(target=lambda: transfer(1)) threads.append(t2) for t in threads: t.start() vip_thread = threading.Thread(name="Processing transfer line", target=handle_amount) vip_thread.start() for t in threads: t.join() vip_thread.join() 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, multiple threads are running to perform transfer (send the transfer amount into the queue).
Then run a vip channel (separate thread) to process the transfer business of the academic committee account.
At the same time, a thread monitoring the queue is also running to print the task status of the queue at regular intervals.
The following is the running result. The results of several runs are correct.
After several operations, the final account balance is 100, and the transformation is successful.
summary
In this article, the academic committee shared the thread safe Queue to solve the problem of concurrent transfer.
In fact, the code can be optimized again. In order to control the length, there are a lot of codes. I hope readers can read and learn to master the use of queues first.
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!