2012-06-18 128 views
1

我對Python編程還很陌生,線程不是我的專業領域。我有一個問題,我希望這裏的人可以幫助我。線程完成時通知主線程

任務:作爲我的碩士論文的一部分,我需要製作一個涉及多人遊戲能力的混合現實遊戲。在我的遊戲設計中,每個玩家可以設置一組陷阱,其中每個陷阱都在特定時間段內有效,例如, 30秒。爲了在所有玩家中保持一致的遊戲狀態,所有的時間檢查都需要在服務器端完成,這是用Python實現的。

我決定啓動一個python線程,每次玩家放置一個新的陷阱並在線程上運行一個定時器。所有這一切都很好,但真正的問題出現時,我需要通知主線程,時間到了這個特定的陷阱,所以我可以溝通相同的客戶端(Android設備)。

我嘗試創建一個隊列,並在任務完成時將信息插入到隊列中,但我無法做一個queue.join(),因爲它會將主線程置於保持狀態直到任務完成,這不是我需要的也不是理想的,因爲主線始終與客戶溝通,如果停止,那麼與球員的所有溝通都將陷入停滯。

我需要運行定時器的輔助線程來告訴主線程,一旦時間用完,時間已經用完併發送陷阱的ID,以便我可以傳遞這些信息給android客戶端刪除它。我怎麼能做到這一點?

就如何實現這一任務,可以在不啓動一個極大的線程來實現任何其他建議,也歡迎.. :) :)

在此先感謝您的幫助..

乾杯

回答

2

我終於找到了用python編寫的一個很好的小任務調度程序,實際上它非常輕便,可以很方便地使用回調機制來安排事件的日後時間或日期,該機制允許子線程返回一個值到主線程通知主線程其狀態以及作業是否成功完成。

人在那裏,誰需要一個類似的功能作爲一個在問題和不想討價還價各地的線程可以使用該調度程序來安排他們的活動,並得到一個回調時,事件做

這裏鏈接到APScheduler

1

在主線程中完成所有定時器的完成可能會更容易一些 - 有一個定時器的列表,您可以繼續添加新的定時器。每個計時器實際上並不是做的任何事情,它只是有一段時間它會關閉 - 如果你在任意一輪工作比在實時工作更容易,但仍然可行。每個時間間隔,主循環都應該檢查所有這些內容,並查看它們是否是時間(或過去的時間),以便它們過期 - 如果是,將它們從列表中刪除(當然,要小心從列表中刪除項目,重複 - 它可能不會做你期望的)。

如果你有很多定時器,並通過性能分析,找出通過所有這些運行的每一個間隔花費你太多的時間,一個簡單的優化將讓他們在一個heapq - 這將讓他們爲你排序,所以你知道第一個還沒有過期之後,其餘的都沒有。喜歡的東西:

while True: 
    if not q: 
     break 
    timer = heapq.heappop(q) 
    if timer.expiry <= currenttime: 
     # trigger events 
    else: 
     heapq.heappush(q) 
     break 

這確實還是花費你一個多餘的流行/推對的,但它很難看,你會怎麼做的更好 - 再次,做這樣的事情:

for timer in q: 
    if timer.expiry <= currenttime: 
     heapq.heappop(timer) 
     # trigger events 
    else: 
     break 

可能會有細微的錯誤因爲列表迭代器(heapq中的函數在序列上工作並使用副作用,而不是由於某種原因存在成熟的heapq類)通過跟蹤它們所處的索引來工作 - 因此,如果刪除當前元素,你把所有東西都推到左邊一個索引後面,然後跳過下一個索引。

唯一重要的是,currenttime在主循環中的每個間隔都會一致地更新(或者,如果您的心臟是基於系統時鐘實時設置的),並且timer.expiry以相同單位 - 如果你有一個'輪'的概念,並且一個陷阱持續六輪,當它被放置時,你會做heapq.heappush(q, Timer(expiry=currenttime+6)

如果你確實想要這樣做,多線程方式,你有一個生產者/消費者隊列清理的方式將工作 - 你只需要不使用Queue.join()。相反,當線程中的計時器用完時,它會調用q.put(),然後死亡。主循環將使用q.get(False),這將避免阻塞,否則q.get(True, 0.1)將阻塞至多0.1秒 - 超時可以是任何正數;仔細調整它,以便在阻塞足夠長的時間之間進行最佳平衡,以便客戶注意並讓事件延遲,因爲他們只是錯過了按時排隊。

+0

感謝您的快速回復..我一定會看看堆的想法,看看我是否可以在我的情況下使用它。我有一個問題,但關於多線程的想法: – vivek86

+0

什麼時候我應該精確地做q.get()?因爲所有線程都在同時運行,我是否需要在主線程中編寫一個無限循環,不斷檢查所有線程以及它們是活着還是死掉,然後從它們獲取信息? 我想要或想到的東西是某種通知給主線程的東西。對於例如假設有10個線程正在運行,除了主線程都在不同的時間和不同的持續時間開始。並假設thread_4的計時器剛剛用完,它應該通知主線程它的時間到了。 – vivek86

+1

@ vivek86隊列是所有線程之間共享的生產者 - 消費者隊列。工作者線程是生產者 - 當他們的計時器用完時他們調用'q.put(timer_info)'。也就是說,隊列是您的通知機制。主線程與我所描述的單線程案例有一個非常相似的循環 - 它將所有內容依次從隊列中取出並處理。它不需要檢查每個線程,甚至不需要知道有多少線程正在運行 - 一旦線程通過隊列發送了通知,它就沒有其他任何操作可以退出(除非您重用它們以提高效率)。 – lvc

0

主線程創建一個隊列和一堆工作線程,它們是 從隊列中提取任務。只要隊列爲空,所有工作線程都會阻塞並且什麼都不做。當一個任務被放入隊列中時,一個隨機的 工作線程獲取任務,它是否工作並準備就緒後立即休眠。通過這種方式,您可以重複使用一個線程而不需要 創建一個新的工作線程。

當你需要停止線程時,你把一個kill對象放入隊列 ,它告訴線程關閉而不是阻塞隊列。

+0

謝謝..會看看它..:) :) – vivek86

+0

使用固定數量的工作線程的問題(實際上,線程的問題通常是這個問題)是OP最可能關心在正確的時間開始的定時器。工作線程從工作隊列中讀取數據是最有意義的,當你不關心*什麼時候開始的時候,只要有一個工作者可用就開始工作。 – lvc