1. 程式人生 > 程式設計 >Python多執行緒的退出控制實現

Python多執行緒的退出控制實現

日常前言

最近接 到一個搶票的爬蟲外包,那個網站及其之撈,訪問購票地址竟然還要排隊,在購票高峰臨時升一下伺服器配置不行嗎…沒辦法,甲方爸爸的要求還得做啊,其中一個障礙便是目標網站的後端限制了訪問頻次,俗話說:“上有政策,下有對策。” 立刻想到了多執行緒 + 多代理的方式進行訪問。

Python多執行緒的退出控制實現

但此時問題便來了,多代理還好說,再寫個爬蟲爬一堆下來就好,多執行緒可就麻煩多了,多執行緒一旦發出去了,基本等同於失控的狀態,你無法去結束或者是重啟一個執行緒,最多隻能是獲取執行緒的資訊,沒有實際的控制權,而且Python官方也沒有提供相應的結束函式。那麼接下來,讓我們來好好聊聊解決這個問題的思路。

單執行緒的結束

說實話,會百度在程式世界是一個優秀的習慣,不然怎麼會有這麼一張表情包呢

Python多執行緒的退出控制實現

但是百度這一次卻不盡人意,搜了很久,結果不盡人意,基本上所有的搜尋結果都告訴我只有結束單個執行緒的方法,我也試過迴圈使用百度的結束函式,但最終都只能是結束的當前的這一個執行緒,無法達到目標。

貼一段搜到的單執行緒結束程式碼示例

def _async_raise(tid,exctype):
 tid = ctypes.c_long(tid)
 if not inspect.isclass(exctype):
  exctype = type(exctype)
 res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,ctypes.py_object(exctype))
 if res == 0:
  raise ValueError("invalid thread id")
 elif res != 1:
  ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,None)
  raise SystemError("PyThreadState_SetAsyncExc failed")
  
def stop_thread(thread):
 _async_raise(thread.ident,SystemExit)

那怎麼結束多個執行緒呢?

既然度娘也搜不到,那就自己探索,開啟python threading模組的官方文件,其中一個daemon屬性進入了視野,單詞翻譯過來便是守護程序,相信大家應該或多或少的聽到過,以下是官方的釋義,大概意思就是隻要在啟動執行緒之前設定了這個屬性為True,當父程序結束時,所有的子程序跟著全部結束,這樣就好辦了,接下來看看程式碼部分。

daemon
A boolean value indicating whether this thread is a daemon thread (True) or not (False). This must be set before start() is called,otherwise RuntimeError is raised. Its initial value is inherited from the creating thread; the main thread is not a daemon thread and therefore all threads created in the main thread default to daemon = False.

完整程式碼

import threading,time,random

class Messy:
 def __init__(self):
  self.__messy = 0

 def m(self,i):
		# 隨機時間進行列印
  time.sleep(random.random()*2)
  print(i)
  if i == 1:
   self.__messy = 1

 def main(self):
  Threads = []
  # 將會啟動10個執行緒,執行緒id為 1 時全部執行緒終止!
  for i in range(10):
   t = threading.Thread(target=self.m,args=(i,))
   t.daemon = 1
   Threads.append(t)
  # 啟動所有執行緒
  for i in Threads:
   i.start()
  # 當標誌位【 messy 】時所有多執行緒結束
  while 1:
   if self.__messy:
    break
  print('執行緒已退出!')

Messy().main()
# 繼續執行後續程式
for i in range(5):
 print('yeah!')

此時,main這個函式對於多執行緒來講,便是父程序,也就是守護程序。預計會進行10次迴圈的數字列印,但是當self.__messy這個標誌位為真時,所有的剩餘子執行緒將不會再執行,直接結束進行後續的操作

e.g:如下圖便只打印了四次

Python多執行緒的退出控制實現

最後

目前來講,用設定主執行緒退出的方法是可以完成現在這個搶票的目標。

但是後來發現其實這麼做也會帶來很多壞處,直接殺掉所有子執行緒對系統來說是一個很粗魯的行為,如果涉及到的操作包括了檔案資料、資料庫資料的改動的話,記憶體無法被合理釋放(之前就遇到過CPU莫名佔用滿),極有可能造成資料丟失甚至系統中斷

我這裡只是一個搶票的小程式,子執行緒只用到了POST,網路請求中斷帶來的影響還是相對來講比較小的,所以大家酌情使用本篇所介紹的方法。

本文作者: Messy
原文連結:https://www.messys.top/detail/78

到此這篇關於Python多執行緒的退出控制實現的文章就介紹到這了,更多相關Python多執行緒退出控制內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!