Python的線程使用隊(duì)列Queue來改造轉(zhuǎn)賬場景
前篇我們了隊(duì)列Queue和轉(zhuǎn)賬場景這次趁熱學(xué)委展示一下使用隊(duì)列解決轉(zhuǎn)賬場景的問題。
一、看看轉(zhuǎn)賬場景的問題
前面有兩篇文章展示了轉(zhuǎn)賬反復(fù)讀寫amount,導(dǎo)致結(jié)果出錯(cuò)。
xuewei_account = dict() xuewei_account['amount'] = 100 # amount為負(fù)數(shù)即是轉(zhuǎn)出金額 def transfer(money): ? ? for i in range(100000): ? ? ? ? xuewei_account['amount'] = xuewei_account['amount'] + money
我們前幾篇使用多個(gè)線程反復(fù)轉(zhuǎn)長:+1和-1。
按常理,結(jié)果應(yīng)該仍舊是100.
這個(gè)是全部代碼:
import random
import threading
import datetime
import time
xuewei_account = dict()
xuewei_account['amount'] = 100
# amount為負(fù)數(shù)即是轉(zhuǎn)出金額
def transfer(money):
? ? for i in range(100000):
? ? ? ? xuewei_account['amount'] = xuewei_account['amount'] + money
# 創(chuàng)建20個(gè)任務(wù)重復(fù)給學(xué)委賬戶轉(zhuǎn)賬
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("活躍線程數(shù):", threading.active_count())
print("活躍線程:", threading.current_thread().name)
print("學(xué)委賬戶余額:", xuewei_account)等待所有轉(zhuǎn)賬線程運(yùn)行結(jié)束,我們看到結(jié)果是錯(cuò)誤的:

二、這種問題怎么使用隊(duì)列來解決呢?
前面說了,多線程反復(fù)讀寫共享數(shù)據(jù),是問題的根源。
改代碼為同步互斥模式,保證任意一個(gè)時(shí)間一個(gè)線程更新共享數(shù)據(jù),那么問題就解決了。(這前面也展示了,用的是Lock鎖的方案)
這個(gè)能怎么用隊(duì)列呢?
可以先思考10秒,根據(jù)學(xué)習(xí)到的加鎖和隊(duì)列的特性,想想這個(gè)怎么做。
好,答案現(xiàn)在揭曉:
Queue這個(gè)隊(duì)列有多個(gè)函數(shù),一個(gè)是put函數(shù),一個(gè)是get函數(shù)。
一個(gè)負(fù)責(zé)放入數(shù)據(jù)到隊(duì)尾,一個(gè)可以從對頭取出元素。
剛好適合轉(zhuǎn)賬業(yè)務(wù),我們是不是可以把每次轉(zhuǎn)賬操作變成一個(gè)一個(gè)指令/事件。 比如下面的:
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個(gè)線程,每個(gè)10萬次數(shù)據(jù)讀寫,共200萬個(gè)事件。
所以我們可以把這個(gè)事情轉(zhuǎn)換為:200萬個(gè)轉(zhuǎn)賬事件。
因?yàn)镼ueue是線程安全的,所以我們可以并發(fā)200萬次轉(zhuǎn)賬,另外交給一線程進(jìn)行轉(zhuǎn)賬處理。
這樣就保證每次只有一個(gè)線程對xuewei_account學(xué)委賬戶進(jìn)行讀寫。
改造,使用隊(duì)列來解決問題
展示代碼:
import random
import threading
import datetime
import time
import queue
q = queue.Queue()
xuewei_account = dict()
xuewei_account['amount'] = 100
# amount為負(fù)數(shù)即是轉(zhuǎn)出金額
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監(jiān)控", target=monitor_q)
q_thread.start()
# 創(chuàng)建20個(gè)任務(wù)重復(fù)給學(xué)委賬戶轉(zhuǎn)賬
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="處理轉(zhuǎn)賬專線", target=handle_amount)
vip_thread.start()
for t in threads:
? ? t.join()
vip_thread.join()
print("-" * 16)
print("活躍線程數(shù):", threading.active_count())
print("活躍線程:", threading.current_thread().name)
print("學(xué)委賬戶余額:", xuewei_account)這里運(yùn)行了多個(gè)線程執(zhí)行轉(zhuǎn)賬(發(fā)送轉(zhuǎn)賬金額進(jìn)隊(duì)列)。
然后運(yùn)行一個(gè)vip通道(單獨(dú)線程)處理學(xué)委賬戶的轉(zhuǎn)賬業(yè)務(wù)。
同時(shí)也運(yùn)行了一個(gè)監(jiān)控隊(duì)列的線程,每隔一段時(shí)間打印隊(duì)列的任務(wù)情況。
下面是運(yùn)行結(jié)果,運(yùn)行幾次結(jié)果都是正確的。

運(yùn)行幾次最終賬戶余額都是100, 改造成功。
三、總結(jié)
本篇學(xué)委分享了線程安全的隊(duì)列Queue解決并發(fā)轉(zhuǎn)賬問題。
其實(shí)代碼還可以再度優(yōu)化的,為了控制篇幅,代碼也不少,希望讀者朋友們能夠先看熟學(xué)會(huì),掌握隊(duì)列的使用。
到此這篇關(guān)于Python的線程使用隊(duì)列來改造轉(zhuǎn)賬場景的文章就介紹到這了,更多相關(guān)Python使用隊(duì)列來改造轉(zhuǎn)賬場景內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python實(shí)現(xiàn)RGB與YCBCR顏色空間轉(zhuǎn)換
這篇文章主要介紹了python實(shí)現(xiàn)RGB與YCBCR顏色空間轉(zhuǎn)換,RGB與YCbCr顏色空間概念的與變換關(guān)系,包括內(nèi)容灰度值和亮度的關(guān)系、RGB顏色空間與顏色控制、YCbCr顏色空間及與RGB的變換關(guān)系,需要的小伙伴可以參考一下2022-03-03
解決pycharm下載庫時(shí)出現(xiàn)Failed to install package的問題
很多小伙伴遇到pycharm下載庫時(shí)出現(xiàn)Failed to install package不知道怎么解決,下面小編給大家?guī)砹私鉀Q方法,需要的朋友參考下吧2021-09-09
python中py文件與pyc文件相互轉(zhuǎn)換的方法實(shí)例
pyc是一種二進(jìn)制文件,是由py文件經(jīng)過編譯后,生成的文件,下面這篇文章主要給大家介紹了關(guān)于python中py文件與pyc文件相互轉(zhuǎn)換的相關(guān)資料,需要的朋友可以參考下2022-05-05
使用 Python 合并多個(gè)格式一致的 Excel 文件(推薦)
這篇文章主要介紹了使用 Python 合并多個(gè)格式一致的 Excel 文件,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-12-12
解決使用pip安裝報(bào)錯(cuò):Microsoft?Visual?C++?14.0?is?required.
對于程序員來說,經(jīng)常pip安裝自己所需要的包,大部分的包基本都能安裝,但是總會(huì)遇到包安裝不了的問題,下面這篇文章主要給大家介紹了關(guān)于如何解決使用pip安裝報(bào)錯(cuò):Microsoft?Visual?C++?14.0?is?required.的相關(guān)資料,需要的朋友可以參考下2022-09-09
淺談python數(shù)據(jù)結(jié)構(gòu)之動(dòng)態(tài)規(guī)劃
這篇文章主要介紹了淺談python數(shù)據(jù)結(jié)構(gòu)之動(dòng)態(tài)規(guī)劃,可能很多小伙伴會(huì)覺得這個(gè)詞很陌生,覺得這是一種很復(fù)雜的思想,學(xué)習(xí)起來很困難,其實(shí)并不是這樣,動(dòng)態(tài)規(guī)劃所講述的知識(shí)與動(dòng)態(tài)與規(guī)劃并無太大關(guān)聯(lián),需要的朋友可以參考下2023-07-07
anaconda虛擬環(huán)境python?sklearn庫的安裝過程
Anaconda是專注于數(shù)據(jù)分析的Python發(fā)行版本,包含了conda、Python等190多個(gè)科學(xué)包及其依賴項(xiàng),這篇文章主要給大家介紹了關(guān)于anaconda虛擬環(huán)境python?sklearn庫的安裝過程,需要的朋友可以參考下2023-11-11
Python?OpenCV實(shí)現(xiàn)簡單的顏色識(shí)別功能(對紅色和藍(lán)色識(shí)別并輸出)
Python?OpenCV可以用來進(jìn)行顏色識(shí)別,可以通過讀取圖像的像素值,來判斷像素點(diǎn)的顏色,從而實(shí)現(xiàn)顏色識(shí)別,這篇文章主要給大家介紹了關(guān)于Python?OpenCV實(shí)現(xiàn)簡單的顏色識(shí)別功能(對紅色和藍(lán)色識(shí)別并輸出)的相關(guān)資料,需要的朋友可以參考下2023-12-12

