建立日期: 2020/05/16, 併入 Tool.py
修訂日期: None
相關軟體資訊:
Win 10 | Python 3.7.6 |
說明: 本文請隨意引用或更改,只須標示出處及作者,作者不保證內容絕對正確無誤,如造成任何後果,請自行負責.
自建執行緒管理
在底層的 _threading 庫中, 執行緒結束是沒有任何通知的, 上層 threading 庫中有提供一些功能, 總覺得還是很難搞, 所以自己就寫了一個class, 來處理這類的事.
處理方法
- 所有的執行緒使用同一個使用者的函式.
- 建立一個待處理列表, 其中放的是使用者函式的引數tuple.
- 建立一個佇列 queue, 內容是正在進行的執行緒, 以獨立的識別碼作為 key.
- 建立一個使用函式返回 False 的出錯佇列, 可以再排入待處理列表.
- 建立內部執行緒, 用來執行使用者函式, 如果使用者函式返回False, 將其加入出錯佇列; 如果使用者函式出錯但不返回False, 就會被認為已完成. 不管有沒有出錯, 都會從進行的執行緒佇列中移除.
- 建立一個執行緒管理的主執行緒, 負責將待處理列表中的專案加入到正在進行的執行緒佇列 queue.
- 提供幾個函式供查詢 - 已完成執行緒的數目, 未完成執行緒的數目, 進行的執行緒佇列 queue是否已滿, 所有的執行緒是否已完成.
- 提供一個屬性 stop, True 只能用來停止”將要進行”的所有執行緒, 進行中的執行緒, 是無法停止的.
- 還有一個 fail 引數, 用來指定如果有使用者函式返回 False 時, 要執行的動作, 比如反爬蟲時, 可能要暫停等待一段時間, 才能繼續.
使用方式
from time import sleep
def f(a, b):
print(a*10+b)
def error():
sleep(1)
args = [(a, b) for a in range(10) for b in range(10)]
T = Thread(f, args, fail=error, size=20)
while not T.all_finished():
pass
print('All jobs done !')
程式碼:
import _thread
class Thread():
def __init__(self, func, sequence, fail=None, size=40):
"""
Manage jobs for threading by list.
: Parameters
func - callable method to thread.
sequence - list of tuple, each arguments for func.
fail - callable method if func return Fail.
size - max size of thread queue.
: Return
Obejct of Thread manager.
"""
self.func = func
self.fail = fail
self.all = sequence
self.total = len(self.all)
self.temp = {}
self.queue = {}
self.size = size
self.stop = False
if callable(self.func) and isinstance(sequence, (tuple, list)):
_thread.start_new_thread(self._host, ())
def all_finished(self):
"""
Return True if all threads finished.
"""
return True if (
sum(map(len, [self.queue, self.all, self.temp]))==0) else False
def jobs_done(self):
"""
Return the number of jobs done.
"""
return self.total - self.jobs_left()
def jobs_left(self):
"""
Return the number of jobs not finished.
"""
return len(self.all) + len(self.tmp) + len(self.queue)
def queue_is_full(self):
"""
Return True if queue is full.
"""
return True if len(self.queue) == self.size else False
def _get_a_key(self):
"""
Get an integer ID for each new thread.
"""
for i in range(self.size):
if i not in self.queue:
return i
return None
def _host(self):
"""
Manager of all threads for thread run, failed process.
"""
while True:
if self.stop:
break
if len(self.all) == 0 and len(self.queue) == 0:
self.stop = True
length = min(self.size-len(self.queue), len(self.all))
for i in range(length):
self._queue_insert(self.func, self.all[i])
self.all = self.all[length:]
if len(self.temp) != 0:
for key, value in self.temp.items():
self.all.append(value)
del self.temp[key]
if callable(self.fail):
self.fail()
def _queue_delete(self, key):
"""
Delete thread in queue after thread done.
"""
del self.queue[key]
def _queue_insert(self, func, value):
"""
Run thread and add it into queue.
: Parameters
func - callable function for thread
value - tuple, arguements for func.
: Return
None
"""
key = self._get_a_key()
self.queue[key] = value
_thread.start_new_thread(self._thread_func, (func, key, value))
def _thread_func(self, func, key, value):
"""
Internal thread for control of user thread.
: Paramters
func - callable function for thread
key - integer ID for each new thread.
value - tuple, arguements for func.
: Return
None
"""
if self.stop:
return
if func(*value) == False:
self.temp[key] = value
self._queue_delete(key)
本作品採用《CC 協議》,轉載必須註明作者和本文連結