首頁 >後端開發 >Python教學 >並發模式:主動對象

並發模式:主動對象

Mary-Kate Olsen
Mary-Kate Olsen原創
2024-12-24 19:27:20749瀏覽

Concurrency Patterns: Active Object

介紹

主動物件模式是一種同時設計模式,它將方法執行方法呼叫解耦。此模式的主要目標是透過在單獨的執行緒中執行操作來引入異步為,同時向客戶端提供同步介面。這是透過訊息傳遞、請求佇列和調度機制的組合來實現的。

關鍵零件

  1. Proxy:代表客戶端的公共介面。更簡單地說,這就是客戶端將要互動的內容。它將方法呼叫轉換為對活動物件的請求。
  2. 調度器:管理請求佇列並決定請求執行的順序。
  3. Servant:包含被呼叫方法的實際實作。這就是實際計算邏輯的所在。
  4. 啟動佇列:儲存來自代理程式的請求,直到排程器處理它們。
  5. Future/Callback:非同步計算結果的佔位符。

工作流程

  1. 客戶端呼叫代理上的方法。
  2. 代理程式建立請求並將其放入啟動佇列中。
  3. 調度程序接收請求並將其轉發給servant執行。
  4. 結果透過 future 物件傳回給客戶端。

使用案例

  • 需要可預測執行模式的即時系統。
  • GUI 應用程式保持主執行緒回應。
  • 用於處理非同步請求的分散式系統。

執行

假設我們需要進行計算,可能是 API 呼叫、資料庫查詢等。我不會實現任何異常處理,因為我太懶了。

def compute(x, y):
    time.sleep(2)  # Some time taking task
    return x + y

沒有活動對像模式

以下是我們如何在不使用主動物件模式的情況下處理並發請求的範例。

import threading
import time


def main():
    # Start threads directly
    results = {}

    def worker(task_id, x, y):
        results[task_id] = compute(x, y)

    print("Submitting tasks...")
    thread1 = threading.Thread(target=worker, args=(1, 5, 10))
    thread2 = threading.Thread(target=worker, args=(2, 15, 20))

    thread1.start()
    thread2.start()

    print("Doing other work...")

    thread1.join()
    thread2.join()

    # Retrieve results
    print("Result 1:", results[1])
    print("Result 2:", results[2])


if __name__ == "__main__":
    main()

上述方法的缺點

  • 執行緒管理:直接管理執行緒會增加複雜性,尤其是隨著任務數量的增加。

  • 缺乏抽象:客戶端負責管理執行緒的生命週期,將任務管理與業務邏輯耦合。

  • 可擴充性問題:如果沒有適當的佇列或排程機制,就無法控制任務執行順序。

  • 回應能力有限:客戶端必須等待執行緒加入才能存取結果。

使用主動物件模式實現

下面是主動物件模式的 Python 實現,使用執行緒和佇列來執行與上面相同的操作。我們將一一介紹每個部分:

MethodRequest: 封裝方法、參數和用於儲存結果的 Future。

def compute(x, y):
    time.sleep(2)  # Some time taking task
    return x + y

調度程式:在單獨的執行緒中持續處理來自activation_queue的請求。

import threading
import time


def main():
    # Start threads directly
    results = {}

    def worker(task_id, x, y):
        results[task_id] = compute(x, y)

    print("Submitting tasks...")
    thread1 = threading.Thread(target=worker, args=(1, 5, 10))
    thread2 = threading.Thread(target=worker, args=(2, 15, 20))

    thread1.start()
    thread2.start()

    print("Doing other work...")

    thread1.join()
    thread2.join()

    # Retrieve results
    print("Result 1:", results[1])
    print("Result 2:", results[2])


if __name__ == "__main__":
    main()

Servant:實作實際邏輯(例如,計算方法)。

class MethodRequest:
    def __init__(self, method, args, kwargs, future):
        self.method = method
        self.args = args
        self.kwargs = kwargs
        self.future = future

    def execute(self):
        try:
            result = self.method(*self.args, **self.kwargs)
            self.future.set_result(result)
        except Exception as e:
            self.future.set_exception(e)

Proxy:將方法呼叫轉換為請求並傳回結果的 Future。

import threading
import queue


class Scheduler(threading.Thread):
    def __init__(self):
        super().__init__()
        self.activation_queue = queue.Queue()
        self._stop_event = threading.Event()

    def enqueue(self, request):
        self.activation_queue.put(request)

    def run(self):
        while not self._stop_event.is_set():
            try:
                request = self.activation_queue.get(timeout=0.1)
                request.execute()
            except queue.Empty:
                continue

    def stop(self):
        self._stop_event.set()
        self.join()

客戶端:非同步提交任務並在需要時檢索結果。

import time


class Servant:
    def compute(self, x, y):
        time.sleep(2)
        return x + y

優點

  • 解耦介面:客戶端可以呼叫方法而無需擔心執行細節。
  • 響應性:非同步執行確保客戶端保持回應。
  • 可擴充性:支援多個並發請求。

缺點

  • 複雜度:增加架構複雜度。
  • 開銷:需要額外的資源來管理執行緒和佇列。
  • 延遲:非同步處理可能會引入額外的延遲。

結論

主動物件模式是用於管理多執行緒環境中的非同步操作的強大工具。透過將方法呼叫與執行分離,它可以確保更好的回應能力、可擴展性和更清晰的程式碼庫。雖然它具有一定的複雜性和潛在的效能開銷,但它的好處使其成為需要高並發和可預測執行的場景的絕佳選擇。然而,它的使用取決於當前的特定問題。與大多數模式和演算法一樣,不存在一刀切的解決方案。

參考

維基百科 - 活動對象

以上是並發模式:主動對象的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn