2009-02-19 214 views
31

我需要在交互式應用程序中管理CPU繁重的多任務作業。正如背景一樣,我的具體應用是工程設計界面。當用戶調整模型的不同參數和選項時,多個模擬會在後臺運行,並在結束時顯示結果,甚至可能在用戶仍在編輯值時發生。由於多個模擬需要可變時間(有些是毫秒,有些需要5秒,有些需要10分鐘),但基本上是儘可能快地獲得反饋,但通常會中止以前開始但現在不再需要的作業,因爲用戶的更改已使其失效。不同的用戶更改可能會使不同的計算失效,因此我可能隨時運行10個不同的模擬。有些模擬有多個部分有相關性(模擬A和B可以單獨計算,但我需要他們的結果來種子模擬C,因此我需要等待A和B在開始C之前先完成)。多線程作業隊列管理器

我覺得非常確信處理這種應用程序的代碼級方法是某種多線程作業隊列。這包括提交執行作業,設置任務優先級,等待作業完成,指定依賴關係(完成此作業,但僅在作業X和作業Y完成後),取消符合某些標準的作業子集,查詢什麼內容工作依然存在,設置工作者線程數和優先級等等。多平臺支持也非常有用。

這些並不是新的想法或軟件的願望,但我在我的應用程序的早期設計階段,我需要選擇哪些庫用於管理這些任務。我過去曾在C寫過自己的粗線程經理(我認爲這是一段經文),但我想用現代工具來開展工作,而不是我以前的黑客。

第一個想法是運行到OpenMP,但我不確定這是我想要的。 OpenMP非常適合在良好的級別進行並行處理,自動展開循環等。在多平臺的同時,它也通過#pragmas侵入你的代碼。但大多數情況下,它不是爲管理大型任務而設計的,特別是取消掛起的作業或指定依賴關係。可能的,是的,但它並不優雅。

我注意到Google Chrome uses such a job manager for even the most trivial tasks.設計目標似乎是讓用戶交互線程儘可能輕便靈活,所以任何可以異步生成的東西都應該是這樣。從查看Chrome源代碼看,這似乎不是一個通用庫,但看到設計如何使用異步啓動來保持快速交互仍然很有趣。這與我正在做的事情類似。

還有一個另外的選擇:

Surge.Act:定義工作升壓樣庫。它建立在OpenMP之上,但確實允許鏈接依賴關係,這很好。看起來似乎沒有一個經理可以被查詢,工作被取消等。這是一個過時的項目,所以它依賴它是可怕的。

Job Queue非常接近我的想法,但它是一個5年的文章,而不是一個支持的庫。

Boost.threads確實有很好的平臺獨立同步,但這不是一個工作管理器。 POCO具有非常乾淨的任務啓動設計,但又不是完整的經理鏈接任務。 (也許我低估了POCO)。

所以雖然有可用的選項,我不滿意,我覺得再次推出自己的圖書館的衝動。但我寧願使用已經存在的東西。即使在搜索過程中(在SO和網上),我還沒有發現任何感覺正確的東西,但我想這應該是一種經常需要的工具,所以肯定有一些社區庫或至少是常見的設計。 在SO有postsjob queues,但似乎不適合。

我在這裏的帖子是問你所有我已經錯過的工具,和/或你如何推出自己的這種多線程作業隊列。

回答

5

我推出了自己的,基於Boost.threads。我很驚訝我從寫這麼小的代碼得到多少回報。如果你沒有找到預先製作的東西,不要害怕推出自己的產品。在Boost.threads和寫自己的經驗之間,這可能比你想象的要容易。

對於預製選項,不要忘記,Chromium被許可非常友好,所以您可能能夠圍繞其代碼推出自己的通用庫。

1

看看boost::future(也看到這個discussionproposal),它看起來像並行了一個非常好的基礎(尤其是它似乎提供了良好的支持C-取決於-ON-A-和B型的情況下)。

我看了一下OpenMP,但是(像你一樣)不相信它對除Fortran/C數字代碼以外的其他任何東西都能很好地工作。英特爾的Threading Building Blocks看起來更有趣。

如果說到這一點,在boost :: thread之上對roll your own不是太難。 [說明:線程farm(大多數人會稱之爲池)從線程安全的函子(任務或作業)queue中提取工作。有關使用示例,請參閱testsbenchmark。我有一些額外的複雜功能來(可選)支持具有優先級的任務,以及執行任務可以在工作隊列中產生更多任務的情況(這使得知道何時所有工作實際上完成了更多問題;引用「正在等待」是可以處理案件的)。無論如何可以給你一些想法。]

+0

優秀。 boost :: future看起來與POCO的ActiveResults非常相似(http://pocoproject.org/poco/docs/Poco.ActiveResult.html)。再說,這不是一個工作隊列管理員,但仍然是一個很棒的工具。 Boost:線程的基礎確實感覺像是製作自定義管理器的最佳低級工具包。 – 2009-02-20 01:23:54

3

會像threadpool對你有用嗎?它基於boost :: threads,基本實現了一個簡單的線程任務隊列,將工作函數傳遞給池線程。

2

您可能想看看 Flow-Based Programming - 它基於異步組件之間的數據塊流式傳輸。有驅動程序的Java和C#版本,以及一些預編碼組件。它本質上是多線程的 - 實際上唯一的單線程代碼是在組件內部,儘管您可以將時序約束添加到標準調度規則中。雖然它可能處於您需要的級別太高的級別,但您可以使用這些內容。

17

我們必須建立我們自己的作業隊列系統,以滿足與你相似的要求(UI線程必須總是在爲33ms響應,作業可以從15-15000ms運行),因爲實在沒有什麼東西可以滿足我們的需求,更不用說高性能。

不幸的是我們的代碼是關於專有專有得到,但我可以給你一些最顯着的特徵:

  • 我們在節目的一開始啓動每個核心一個線程。每個人都從全球工作隊列中抽取工作。作業由一個函數對象和一組相關數據組成(真的是一個func_ptr和void *的詳細說明)。線程0,快速客戶端循環,不允許在作業上工作,但其餘的儘可能抓取。
  • 作業隊列本身應該是無鎖數據結構,例如lock-free singly linked list(Visual Studio comes with one)。避免使用互斥體;對隊列的爭奪驚人地高,並且搶互斥是昂貴的。
  • 將作業的所有必要數據打包到作業對象本身 - 避免將作業的指針返回到主堆中,必須處理作業與鎖之間的爭用以及所有其他緩慢,煩人的東西。例如,所有的模擬參數都應該放入作業的本地數據blob中。結果結構顯然需要是超出工作的東西:你可以通過以下方式來處理這個問題:a)掛起作業對象,即使它們已經完成運行(因此可以使用主線程中的內容),或者b)爲每個作業分配一個結果結構,並將指針填充到作業的數據對象中。即使結果本身不會在工作中生效,這可以有效地讓工作對其輸出內存進行獨佔訪問,因此您不必擔心會出現鎖定問題。

  • 實際上我簡化了一點以上,因爲我們需要精確地編寫哪些作業在哪些內核上運行,所以每個內核都有自己的作業隊列,但這可能對您沒有必要。

+0

你可以介紹一下「精確地指出哪些作業在哪些內核上運行,因此每個內核都有自己的作業隊列」,這是什麼原因,它是否與處理器關聯有關(https://en.wikipedia.org/wiki/Processor_affinity)? – athos 2017-01-24 00:55:03

+1

@athos這是另一種方式:處理器親和力是我們如何說哪​​個作業在哪個核心上運行。我們需要精確地編排事物,以便兩個實時線程能夠在其核心上持續運行而不會有任何搶佔風險,而其他作業則以最大化緩存位置,超線程效率等方式分配給特定硬件核心。一個固定的硬件平臺可以非常緊密地優化。 – Crashworks 2017-03-23 21:51:23

4

微軟正在爲Visual Studio 2010的下一個版本開發一組稱爲併發運行時,並行模式庫和異步代理庫的技術,這可能會有所幫助。併發運行時將提供基於策略的調度,即允許您管理和組合多個調度程序實例(類似於線程池,但實例之間具有關聯和負載平衡),並行模式庫將提供基於任務的編程和帶STL的並行循環編程模型。代理程序庫提供基於代理程序的編程模型,並支持構建併發數據流管道,即管理上述依賴關係。不幸的是,這還沒有發佈,所以你可以在我們的team blog上看到它,或者觀看一些視頻on channel9,還有一個非常大的CTP可供下載。

如果您現在正在尋找解決方案,英特爾的線程構建模塊和boost的線程庫都是很好的庫,現在就可以使用。 JustSoftwareSolutions已發佈std :: thread的實現,該實現與C++ 0x草稿相匹配,當然,如果您正在尋找基於細粒度循環的並行機制,則OpenMP是廣泛可用的。

其他人已經提到的真正挑戰是正確識別並將工作分解爲適合併發執行的任務(即沒有不受保護的共享狀態),理解它們之間的依賴關係並最小化可能發生在瓶頸上的爭用(無論是瓶頸是protecting shared state或確保工作隊列的調度循環是低爭用或無鎖)......並且在沒有安排實現細節泄露到代碼的其餘部分的情況下執行此操作。

-Rick

1

有很多分佈式資源管理器。幾乎滿足您所有要求的軟件是Sun Grid Engine。 SGE被用於一些世界上最大的超級計算機,並且正在積極開發中。

Torque,Platform LSFCondor中也有類似的解決方案。

聽起來你可能想要推出自己的產品,但上述所有功能都有很多。