作為物理學家的計算,我經常運行的程序由許多嵌套for循環 。 目前,我的最外層循環週期,通過數百萬個數據點和各種內部循環探索成千上萬的參數。 我總是擺弄著設置在內部循環的方式,導致運行時間 10秒之間變化,10週。
煩人,這不是一件容易預測多久後運行的程序將每一組的修改。 此外,我的代碼偶爾有錯誤,這使得無限期掛起。 當一個程序的運行時間預計在幾週內衡量,它是令人欣慰地看到定期進度報告。 否則我擔心,該計劃已經悄悄墜毀。
起初,我只是打一個print語句到最外層的環,裝在一個的if - then語句一次只激活1000循環。 打印語句中使用的時間過去了,因為一開始循環和取得的進展來估計剩餘時間。 它看起來有點像這樣(加上一些類型轉換 ):
一 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ( NULL ) ; //Grab starting time. start_time = 時間 (0); / /抓斗的開始時間。 i = 0 ; i < i_end ; i ++ ) { 對 (我= 0;我<i_end;我+ +)( i + 1 ) % 1000 == 0 ) { //Only print every 1000 loops. 如果 ((我+ 1)%1000 == 0)(/ /每1000只打印循環。 ( NULL ) ; //Grab current time. current_time = 時間 (0); / /抓取當前時間。 start_time ;時間跨度= current_time - start_time; / /完成的總時間可以得到 / /除以時間跨度由一小部分已經完成。 / /減去時間跨度後,剩餘時間 / /是左(以秒為單位,常常是混亂)。 ( i + 1 ) / ( i_end + 1 ) - timespan ; time_remaining =跨度/(1 + 1)/(i_end + 1) -時間跨度; ( i + 1 ) / i_end * 100 << "% finished, " 法院 <<(我+ 1)/ i_end * 100 <<“%完成,” "seconds remaining." << endl ; <<time_remaining <<“ 秒”的目標。<<恩德; ) j = 0 ; j < j_end ; j ++ ) { 為 (十 = 0; j <j_end; j + +)( / /做很多的東西在這裡。 ) ) |
這就夠了,直到我改變的設置的內循環的方式,大大提高了運行時間。 第一個通知了幾個小時出現,我認為不能接受緩慢。 然後我試圖使打印語句激活每10循環,加速運行時通知的時間很長,但是,填補日誌文件with兆字節的print statements,拖慢program。 很明顯,快速劈了做需要大量的日常維護。 我需要一個通知系統,可以自動適應短期和長期的運行時間。
我呼籲我的解決方案“自動通知”。 最新版本是1.2版,可在這裡下載 。
特點:
- 直到第一時間通知似乎可以單獨控制的其他通知,並默認為 10秒。
- 之間的時間量控制所有後續通知是由一個變量,它指定一個目標間隔通知。 實際時間將在30%這一目標的(默認 5分鐘)。
- 一個最低數量(默認值是4)通知將印刷的通知()。 這只能激活如果預計運行時間少於所選間隔通知。
- 剩餘時間印數人類可讀格式使用seconds_to_string()函數。 在幾年的時間報導,週,日,小時,分鐘,秒。 不超過 2個單位將被打印在每個語句以減少混亂(雖然此值可定制)。
- 一個 print語句報告的時間過去了,最後的循環,所以估計剩餘時間可以判斷對循環實際上多久了。
- 外層循環可以在任何(正! - 需要解決這個問題!)指數,而不僅僅是 0在上面的例子。
- 最上面的通知選項設置每個循環中,所以多個循環可以配置不同(見 custom_example.cpp)。
- 這可能是一個好主意,把代碼到通知功能,節省您的數據到磁盤,以便在計算機崩潰或斷電,重新啟動該應用程序可以從最後的通知點。 該變量 notification.partial_saves_enabled是為了打開這個不成文的代碼,但您還需要通過一個新的參數的通知()函數包含所需的數據寫入到磁盤。
要求:
- 擬用於在C + +程序,測試使用的g + +編譯器,配有Ubuntu的8.10 64位 。
- 您最外層的循環週期,必須對許多指數(幾十個或更多)。 該循環可以在任何索引你想要的,但需要增加1在每個循環。
- 需要的iostream,iomanip和矢量庫(可在Ubuntu默認情況下)。
該方案是分成3個文件:包含數據類型common_declarations.hpp定義和函數聲明,函數定義為common_functions.cpp已通知()和sec2human(),而example.cpp只是一個例子迴路,它可以使用自動通知。
這個師是沒有必要的,但我發現這是一個很好的方法來組織大型軟件項目。 通過這種方式,廣泛使用的功能是很少改變可以聲明和共同文件中定義,並分別從編制計劃,只是使用這些功能。
在Makefile中包含自動通知編譯兩個步驟來說明這種技術。 在加入許多功能,以我的版本的共同文件,第一個編譯步驟差不多有一分鐘我的電腦上。 這一步只發生在共同文件編輯,然而,這意味著它很少需要。 第二編譯步驟,另一方面,更頻繁,更快。
順便說一下,common_declarations.hpp包含行“使用命名空間性病”。 我已經看過 ,這是不好的編程習慣,但我沒有遇到任何嚴重後果,然而,和它的方便,不需要現在鍵入“性病::”每次我想使用“法院”。
以下是example.cpp樣子:
一 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | /************************************************* ******* 目的: 這個程序運行一組嵌套的循環 執行無用的計算數 分鐘(具體時間取決於速度 您的計算機和限制的嵌套 循環)。 它的目的是展示 通知()函數。 ************************************************** ******* 阿呆科學家寫的 首先寫道:2009-02-26 最後更新:2009年3月8日 ************************************************** ******/ / /頭文件“common_declarations.hpp”聲稱很多 / /函數,數據類型和常量。 為了使用 / /函數中聲明它,你必須鏈接此方案 / /與目標代碼使用common_functions.cpp了。 #包括“common_declarations.hpp” 詮釋的main()( / /聲明計數器和限額的循環。 0 ,i,j,i_start = 30 ,i_end = 200000 ,j_end = 200000 ; 長期臨時= 0,i和j,i_start = 30,i_end = 200000,j_end = 200000; / /初始化變量通知()。 notification_struct通知; / /更改這個字符串以任何你想要的。 "Example loop" ;通知。 前綴 =“為例循環”; / /你的起始索引可能會有所不同。 i_start ;通知。starting_index = i_start; / /你的結局也可能指數將有所不同。 i_end - notification. starting_index ;通知。num_loops = i_end -通知。starting_index; i = notification. starting_index ; i < i_end ; i ++ ) { 對 (我=通知。starting_index;我<i_end;我+ +)( / /打印週期的剩餘時間。 ;通知(通知我); j = 0 ; j < j_end ; j ++ ) { 為 (十 = 0; j <j_end; j + +)( / /計算一無是處。 ( i * j * j * j - 2 * i + 3 * j ) ;氣溫+ =(我* j * j *的J - 2 * 3 *我+ j)條 ; )/ /結束的內部循環。 )/ /結束外循環。 / /記錄時間結束課程。 time ( NULL ) ;通知。end_time = 時間 ( 空 ); notification. end_time - notification. start_time ;通知。time_total =通知。end_time -通知。start_time; notification. prefix << " took " 法院 <<通知。 前綴 <<“了” notification. time_total ) << endl ; <<seconds_to_string(notification. time_total)<<恩德; / /如果氣溫不使用後,這個方案考慮 / / 0秒。 我想這就是結果了- 02 / /標誌注意到,上述循環是沒有必要的。 返回氣溫; ) |
當運行時,它產生的輸出看起來像這樣(請注意,第一行出現在幾秒鐘內,並隨後通知是因為除了25%的estimated運行時這個計劃是低於默認間隔):
一 2 3 4 5 6 | 例如循環是8.20%。 剩餘時間:1分52秒 例如循環是33.20%。 剩餘時間:1分20秒 例如循環是58.19%。 剩餘時間:51秒 例如循環是83.19%。 剩餘時間:20秒 例如循環以2分1秒 ` |
我改變了循環的限制,加入四零每個 i_end和j_end,但第一線仍然出現在幾秒鐘內:
一 2 | 例如循環是0.00%。 剩餘時間:285年,10週 ` |
很明顯,我沒有等待,一個完成。 但問題是,我很快就知道我會老死世紀前一樣。 順便說一句,我嘗試加入數零到j_end首先,它造成的不快通知採取長的時間才會出現。 這是因為外環需要較長的時間來增加一次。 我還不知道我怎麼想解決這個問題。
自動通知是免費軟件,授權下的GPLv3的 ,而不是CC授權的其他網站的用途。 如果有人通知任何錯誤或有任何建議,為如何改進自動通知,請讓我知道在下面的評論。 我也很好奇,看看別人是如何解決了這個問題,無論是語言寫成英寸
版本歷史
1.2 - 2009年3月8日 -簡化的默認設置,以縮短example.cpp補充custom_example.cpp。
1.1版- 2009-02-27 -取代max和min的時間間隔與target_interval。
1.0 - 2009年2月26日 -原始版本。
最後修改2009年8月2日

















































我很驚訝你沒有使用一個定時器中斷。 沒有開銷,而循環運行,精確控制樣品的時間間隔。 只是需要一些方法來得到循環變量進入中斷處理程序和結果出來。
沒有使用,因為我從來沒有聽說過。 謝謝,我會進行調查。
“生產”這個版本的函數接受一個結構與幾個 GB的數據和autosaves到磁盤。 我想知道如果一個計時器中斷,可能會派遣這麼多的數據以透明的方式? 即整個結構需要通過發送引用作為一個單一的參數,而不進行本地複製的數據(它僅適合到內存了。)
此外,該函數需要被調用在該代碼中的確切位置,而不是內部的內循環,否則將自動保存功能無法正常工作。 如果這一切的可能性,定時器中斷時,有人請點我一些示例代碼。
(編注:此評論最初張貼在這裡 。)
為什麼? 這只是意味著我必須打開多個文件時,我要進行大量的維修方案。
編譯肯定是更快,如果你只改變一出同樣大小的文件100個,但我選擇了創建兩個文件的主要來源:一是經常編輯和大型(30,000行),而第二次被編輯數十天只有有1K線。 Makefile文件編譯成目標代碼大文件,然後鏈接到該對象的代碼的小文件。 此後的大文件,如果只按修訂日期大源文件是較新的比大對象文件。 即使編譯時間的大文件,只是〜10秒1的netbook如果優化被禁用,目前還不清楚,我的編譯時間將增長將快於 CPU速度。 (特別是如果並行克+ +永遠得到體面的。)
我想可以說代碼分割有助於執行“數之間的互聯功能”的原則。 (或者不管它的正式名稱,職能應該的概念,即只有少數互動良好定義的方法。)這在理論上是有吸引力的理想,但似乎沒有惱人的執行允許一些例外。 我並不想改變成一個有用的指引,嚴格的法律,將可能只是我慢下來。
我也寫代碼自己,所以球隊的原因,涉及編程不太相關。 一個良好的版本控制系統如水銀應盡量減少這些問題而已。
是否有任何真正的(即生產力,可擴展性)的原因放棄這種做法,開始把新的功能在不同的文件嗎? 我不是一個專業的程序員,所以我可能會錯過一些計算機科學博士學位會考慮明顯的和令人信服的...
既然你的代碼在GPL許可證(所以基本上你歡迎或至少不介意其他人學習,分享您的代碼),那麼代碼管理很舒服,可實現模塊化 。
最重要的是要記住的是分裂代碼按照它做什麼(邏輯分離)。 說實話,我沒有看過你的代碼,以便它可能並不適用於這種情況下(也許一個真正的大文件是有道理的)。
話雖如此,在最後的一天有沒有硬性的法規,只是發出的指引,從經驗和很多的錯誤:)
優秀點。 感謝您的文章。