自建執行緒管理

Jason990420發表於2020-05-16

建立日期: 2020/05/16, 併入 Tool.py

修訂日期: None

相關軟體資訊:

Win 10 Python 3.7.6

說明: 本文請隨意引用或更改,只須標示出處及作者,作者不保證內容絕對正確無誤,如造成任何後果,請自行負責.

自建執行緒管理

在底層的 _threading 庫中, 執行緒結束是沒有任何通知的, 上層 threading 庫中有提供一些功能, 總覺得還是很難搞, 所以自己就寫了一個class, 來處理這類的事.

處理方法

  1. 所有的執行緒使用同一個使用者的函式.
  2. 建立一個待處理列表, 其中放的是使用者函式的引數tuple.
  3. 建立一個佇列 queue, 內容是正在進行的執行緒, 以獨立的識別碼作為 key.
  4. 建立一個使用函式返回 False 的出錯佇列, 可以再排入待處理列表.
  5. 建立內部執行緒, 用來執行使用者函式, 如果使用者函式返回False, 將其加入出錯佇列; 如果使用者函式出錯但不返回False, 就會被認為已完成. 不管有沒有出錯, 都會從進行的執行緒佇列中移除.
  6. 建立一個執行緒管理的主執行緒, 負責將待處理列表中的專案加入到正在進行的執行緒佇列 queue.
  7. 提供幾個函式供查詢 - 已完成執行緒的數目, 未完成執行緒的數目, 進行的執行緒佇列 queue是否已滿, 所有的執行緒是否已完成.
  8. 提供一個屬性 stop, True 只能用來停止”將要進行”的所有執行緒, 進行中的執行緒, 是無法停止的.
  9. 還有一個 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 協議》,轉載必須註明作者和本文連結
Jason Yang

相關文章