如果命令沒有依賴於對方的狀態,您可以並行他們。有很多方法可以做到這一點,但一個更容易的使用線程包的thread pooling(這需要一個螺紋TCL,在許多平臺上爲標準現在):
package require Thread
set pool [tpool::create -maxworkers 4]
# The list of *scripts* to evaluate
set tasks {
{command 1}
{command 2}
...
{command n}
}
# Post the work items (scripts to run)
foreach task $tasks {
lappend jobs [tpool::post $pool $task]
}
# Wait for all the jobs to finish
for {set running $jobs} {[llength $running]} {} {
tpool::wait $pool $running running
}
# Get the results; you might want a different way to print the results...
foreach task $tasks job $jobs {
set jobResult [tpool::get $pool $job]
puts "TASK: $task"
puts "RESULT: $jobResult"
}
主要tweakable是的大小線程池,默認爲4.(通過-maxworkers
選項tpool::create
我已經明確上面列出的設置它。)的限制選擇最佳的價值取決於有多少CPU內核你有,有多少CPU負載每任務平均產生;你需要衡量和調整...
您還可以使用-initcmd
可選擇預加載池中的每個工作線程與您所選擇的腳本。這是一個放置您的package require
電話的好地方。工作人員全部是完全互相獨立和主線程;他們不分享國家。如果您在單獨的進程中運行每段代碼(但最終會編寫更多代碼來執行協調),您將獲得相同的模型。
[編輯]:這是一個版本,將使用Tcl 8.4,並使用子進程。
namespace eval background {}
proc background::task {script callback} {
set f [open |[list [info nameofexecutable]] "r+"]
fconfigure $f -buffering line
puts $f [list set script $script]
puts $f {fconfigure stdout -buffering line}
puts $f {puts [list [catch $script msg] $msg]; exit}
fileevent $f readable [list background::handle $f $script $callback]
}
proc background::handle {f script callback} {
foreach {code msg} [read $f] break
catch {close $f}
uplevel "#0" $callback [list $script $code $msg]
}
proc accumulate {script code msg} {
puts "#### COMMANDS\n$script"
puts "#### CODE\n$code"
puts "#### RESULT\n$msg"
# Some simple code to collect the results
if {[llength [lappend ::accumulator $msg]] == 3} {
set ::done yes
}
}
foreach task {
{after 1000;subst hi1}
{after 2000;subst hi2}
{after 3000;subst hi3}
} {
background::task $task accumulate
}
puts "WAITING FOR TASKS..."
vwait done
注:任務是產生一個結果Tcl命令,但他們不得打印結果出來;結構碼(在background::task
)處理。這些是子過程;他們彼此不分享任何東西,所以您希望他們做的或者配置的任何東西都必須作爲任務的一部分發送。一個更復雜的版本可以保留子進程的熱池,並且一般工作非常像線程池(由於處於子進程而不是線程而產生的細微差異),但是這比我想寫的代碼更多。
結果代碼(即,例外代碼)爲「ok」爲0,「error」爲1,其他值爲不常見情況。它們正是Tcl 8.6 catch
manual page中記錄的值;這取決於你是否正確地解釋它們。 (我想我還應該添加代碼以使::errorInfo
和::errorCode
變量的內容在出現錯誤的情況下被報告回來,但這會使代碼更加複雜......)
作爲替代方案,也許我可以運行shell命令在後臺將它們推送到各個臨時文件,並在完成執行後收到通知,然後將它們捕獲到主文件中。 我很擔心在同一時間情況下將多個進程寫入同一個文件,不希望輸出文件損壞。 並不真正知道如何表示後臺進程是從tcl腳本內運行完成的。 – egorulz
你可以用'fileevent'完成它;讀取器管道在不再有遠端時變得可讀。 (Writer block ...) –