ego*_*ulz 5 shell redirect background tcl
我有一个tcl脚本,它连续运行多个shell命令.
像这样的东西:
abc.tcl
command 1
command 2
command 3
...
command n
Run Code Online (Sandbox Code Playgroud)
此脚本按以下格式将这些命令的输出打印到文本文件中:
### ### ### ### ### ###
Command name
### ### ### ### ### ###
Command Output
### ### ### ### ### ##
Run Code Online (Sandbox Code Playgroud)
我试图让脚本运行得更快,但使shell命令并行运行而不是串行运行.通过将它们推到后台(命令a&).但我不知道如何保留输出文本文件的格式,就像以前一样.
当我将命令推入后台时,我被迫将其输出附加到临时文件中,但这些文件只是将转储中的命令输出放在一起.难以区分不同的输出.
在某种程度上,我可以将在后台运行的每个命令的输出重定向到单个临时文件(可能临时文件的名称可以具有后台运行进程的进程ID).一旦所有命令都运行,我可以将输出结合到正确的格式中吗?关于如何实现这一目标的任何想法/建议.
如果命令没有相互依赖的状态,您可以并行化它们。有很多方法可以做到这一点,但更简单的方法之一是使用线程包的线程池(这需要线程化的 Tcl,这是当今许多平台上的标准):
\npackage require Thread\n\nset pool [tpool::create -maxworkers 4]\n# The list of *scripts* to evaluate\nset tasks {\n {command 1}\n {command 2}\n ...\n {command n}\n}\n\n# Post the work items (scripts to run)\nforeach task $tasks {\n lappend jobs [tpool::post $pool $task]\n}\n\n# Wait for all the jobs to finish\nfor {set running $jobs} {[llength $running]} {} {\n tpool::wait $pool $running running\n}\n\n# Get the results; you might want a different way to print the results...\nforeach task $tasks job $jobs {\n set jobResult [tpool::get $pool $job]\n puts "TASK: $task"\n puts "RESULT: $jobResult"\n}\nRun Code Online (Sandbox Code Playgroud)\n主要可调整的是线程池的大小,默认限制为 4。(通过我上面明确列出的-maxworkers选项进行设置tpool::create。)选择的最佳值取决于您有多少个 CPU 核心每个任务平均产生多少 CPU 负载;您需要测量和调整\xe2\x80\xa6
您还可以使用该-initcmd选项使用您选择的脚本预加载池中的每个工作线程。这是拨打package require电话的好地方。工作线程彼此完全独立,也完全独立于主线程;他们不共享状态。如果您在单独的进程中运行每段代码,您将获得相同的模型(但最终您将编写更多代码来进行协调)。
[编辑]:这是一个可与 Tcl 8.4 配合使用并使用子进程的版本。
\nnamespace eval background {}\nproc background::task {script callback} {\n set f [open |[list [info nameofexecutable]] "r+"]\n fconfigure $f -buffering line\n puts $f [list set script $script]\n puts $f {fconfigure stdout -buffering line}\n puts $f {puts [list [catch $script msg] $msg]; exit}\n fileevent $f readable [list background::handle $f $script $callback]\n}\nproc background::handle {f script callback} {\n foreach {code msg} [read $f] break\n catch {close $f}\n uplevel "#0" $callback [list $script $code $msg]\n}\n\nproc accumulate {script code msg} {\n puts "#### COMMANDS\\n$script"\n puts "#### CODE\\n$code"\n puts "#### RESULT\\n$msg"\n\n # Some simple code to collect the results\n if {[llength [lappend ::accumulator $msg]] == 3} {\n set ::done yes\n }\n}\nforeach task {\n {after 1000;subst hi1}\n {after 2000;subst hi2}\n {after 3000;subst hi3}\n} {\n background::task $task accumulate\n}\nputs "WAITING FOR TASKS..."\nvwait done\nRun Code Online (Sandbox Code Playgroud)\n注意:任务是产生结果的Tcl命令,但它们不能打印结果;面料代码(在background::task)处理这个问题。这些是子流程;它们彼此之间没有任何共享,因此您希望它们执行或配置的任何内容都必须作为任务的一部分发送。更复杂的版本可以保留子进程的热池,并且一般工作方式非常像线程池(由于处于子进程而不是线程中而存在细微的差异),但这比我想在这里编写的代码要多。
结果代码(即异常代码)对于 \xe2\x80\x9cok\xe2\x80\x9d 为 0,对于 \xe2\x80\x9cerror\xe2\x80\x9d 为 1,在不太常见的情况下为其他值。它们与Tcl 8.6catch手册页上记录的值完全相同;由您来正确解释它们。(我想我还应该添加代码来制作::errorInfo和::errorCode变量内容,但这会使代码变得更加复杂\xe2\x80\xa6)
| 归档时间: |
|
| 查看次数: |
3262 次 |
| 最近记录: |