OptaPlanner 7.32.0.Final版本彩蛋 - SolverManager之批量求解

上一篇介紹了OptaPlanner 7.32.0.Final版本中的SolverManager接口可以實現異步求解功能。本篇將繼續介紹SolverManager的另一大特性 - 批量求解。

適用場景

在日常的規劃系統中,求解一個問題,絕大多數情況下,容許運行的時間較有限,特別是在實時性較高的場景中,可讓引擎運算時間不多。因此,這種情況下,會在啓動了規劃運算後,稍等片刻,即需要從求解程序中獲取結果。但有些情況下,當我們遇到問題規模較大時,引擎無法在較短時間內找到相對最優解;甚至某些情況下,沒有足夠長的運行時間,可行解都可能無法找到。至於原因,可以參考我前面關於OptaPlanner入門文章中關於NPC, NP-Hard問題規模的說明。

因此,在一些規模大、時間要求不高的場景下,我們可以讓引擎在空餘時間自動運算。例如通過定時作業的方式,在非工作時間(例如晚間、節假日等)啓動引擎對大多個規模的問題進行規劃運算;第二天上班的時候,就可獲得運算結果。在發佈SolverManager之前,我們也完全可以針對不同的場景,設計相應的定時作業程序,讓引擎運算自動運行。當然,這種方法與異步規劃的問題一樣,需要一定的系統設計經驗才能把架構設計完美。而7.32.0.Final版本提供的SolverManager接口,則提供一種更簡便的方法來實現些需求。

SolverManager批量規劃特性

詳細一下SolverManager接口,你應該會發現,與Solver對象的solve方法不同,使用SolverManager的sovle方法對一個問題進行求解時,除了把問題對象作爲參數傳入solve方法外,還需要傳入一個problemID作爲參數。其實對於這個參數很好理解,因爲SolverManager可以同時對多個問題進行解,必須存在一種方法來識別不同的問題,規劃完成後,調用方也需要通過指定的識別號,來獲取相應的方案。SolverManager同時對多個問題進行求解時,對問題個數有何要求?它的求解行爲是怎麼樣的呢?

SolverManager批量求解的行爲

可同時求解多少個問題?

其實SolverManager不僅可以實現批量求解問題,而且可以實現同時對多 問題並行求解。通過設置SolverManager的parallelSolverCount屬性,可以設置引擎在批量運算時,可以並行求解的問題數。即當SolverManger啓動求解運算時,會將parallelSolverCount設定的數量的問題載入運算空間並行求解。通常parallelSolverCount值可以根據CPU、內存等計算機資源的情況,及問題的複雜度而推算。若無法判斷此數量,也可以將parallelSolverCount設置爲AUTO,引擎會根據具體情況,自動確定並行運算問題的數量,通常情況下,並行數是CPU核心數量的一半。

值得注意的是,此處的多個問題並行運算,與之前的求解過程多線程運算(Multithreaded incremental solving)是兩個概念。多線程並行運算,指的是引擎在求解一個問題時,會將不同的可能解的子集分成多個線程同時計算(主要是計算約束分數和執行啓發式算法)。而SolverManager的批量求解過程中,parallelSolverCount屬性設定的,是引擎在面對多個問題時,同時求解的問題個數。大家可以設想,如果把Multithreaded incremental solving也啓動起來,令引擎在對一個問題求解時可使用多個CPU核心,同時對多個問題並行求解。這種情況涉及的問題就沒那麼簡單。因此,除非你對問題的複雜程度,CPU的核心和運算能力非常清晰,否則上述兩個功能,還是設置爲自動更好,引擎會根據計算資源運算時的工況,動態地自動確定並行求解的問題個數,及每個問題求解過程中應啓動的線程個數。經歷過單CPU多線程編程的朋友應該知道,多線程可以提高資源利用率,但有時候線程數量控制得不好,性能上卻是起反效果的,最簡單的是CPU的線程切換會消耗一定資源的。

批量求解的作用

在一些不太需要實時規劃,規劃求解不需要太頻繁,運算需時較長的情況,批量求解就可以發揮較好作用。例如需要做一些季度或年度的大型供應鏈計劃,因規劃實休數量較大,問題空間可能非常巨大,需要花費相當長的時間才能得行相對最優解,甚至只能是可行解。可通過批量求解的方式,讓引擎在空餘時間(例如晚上、非工作日)進行運算,從而提高服務器資源的利用率。

基本用法

以下例子是OptaPlanner用戶指南的例子,大家先作參考,目前還沒有時間去研究SolverManager在示例程序中的代碼,暫時也不知道官方示例中是否已經有SolverManager相關代碼;若沒有,稍後的時候我自己試用一下這些功能,再寫一篇東西出來分享給大家。

public class TimeTableService {

    private SolverManager<TimeTable, Long> solverManager;

    // Returns immediately, call it for every dataset
    public void solveBatch(Long timeTableId) {
        solverManager.solve(timeTableId,
                // Called once, when solving starts
                this.findById,
                // Called once, when solving ends
                this.save);
    }

    public TimeTable findById(Long timeTableId) {...}

    public void save(TimeTable timeTable) {...}

}

 

原創不易,如果覺得文章對你有幫助,歡迎點贊、評論。文章有疏漏之處,歡迎批評指正。

本系列文章在公衆號不定時連載,請關注公衆號(讓APS成爲可能)及時接收,二維碼:

http://weixin.qq.com/r/WjtFXSvE2HanrW8_925I (二維碼自動識別)


如需瞭解更多關於OptaPlanner的應用,請發電郵致:[email protected]
或到討論組發表你的意見:https://groups.google.com/forum/#!forum/optaplanner-cn
若有需要可添加本人微信(13631823503)或QQ(12977379)實時溝通,但因本人日常工作繁忙,通過微信,QQ等工具可能無法深入溝通,較複雜的問題,建議以郵件或討論組方式提出。(討論組屬於google郵件列表,國內網絡可能較難訪問,需自行解決)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章