tcl 多线程就像在 c 中一样,很难用过程执行线程
tcl multithreading like in c, having hard time to execute thread with procedure
我曾经在 C 中工作,在那里可以很容易地使用我选择的特定函数创建线程。
现在在 tcl 中我不能使用线程启动我想要的特定功能,我试过这个:
package require Thread
proc printme {aa} {
puts "$aa"
}
set abc "dasdasdas"
set pool [tpool::create -maxworkers 4 ]
# The list of *scripts* to evaluate
set tasks {
{puts "ThisisOK"}
{puts $abc}
{printme "1234"}
}
# 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"
}
我总是得到:
执行错误206: invalid command name "printme"invalid command name "printme"
在执行时
"printme "1234""
从内部调用
"tpool::get $pool $job"
为什么?
你的问题是,Tcl 线程模型与 C 语言中使用的模型非常不同。Tcl 的模型基本上是 'shared nothing by default' 主要基于消息传递的模型。
所以池中的每个线程都是一个独立的解释器,并且对 proc
printme 一无所知。你需要用你需要的过程来初始化这些解释器。
查看 ::tpool::create
命令的文档,它有一个选项可以提供一个 -initcmd
您可以在其中定义或 package require
您需要的东西。
所以试试这个来初始化你的线程:
set pool [tpool::create -maxworkers -initcmd {
proc printme {aa} {
puts "$aa"
}}]
https://www.tcl.tk/man/tcl/ThreadCmd/tpool.htm#M10
更详细地回答您的评论:
不,没有办法让 Tcl 线程像 C 线程一样工作并自由共享对象和过程。这是一个基本的设计决策,允许 Tcl 拥有一个没有大量全局锁的解释器(与例如 CPython 相比),因为大多数事情都是线程本地的并且使用线程本地存储。
但是有一些方法可以使多线程解释器的初始化和使用更容易。一个是 ::tpool::create
中的 -initcmd
参数,它允许您为池中的每个解释器 运行 初始化代码,而无需手动执行。如果您所有的代码都在一个包中,您只需添加一个 package require
并正确初始化您的解释器。
如果你真的想在多个线程之间共享状态,你可以使用::tsv
子命令。它允许您以明确的方式在线程之间共享数组和其他内容。但在幕后,它涉及您可能从 C 中了解到的典型锁和互斥锁来调解访问。
thread
包中还有另一组命令,可让您更轻松地进行初始化。这是 ttrace
命令,它允许您简单地 trace
在一个解释器中执行的内容并在另一个解释器中自动重复它。它非常聪明,只有 shares/copies 你真正用于目标的过程,而不是预先加载所有东西。
我曾经在 C 中工作,在那里可以很容易地使用我选择的特定函数创建线程。
现在在 tcl 中我不能使用线程启动我想要的特定功能,我试过这个:
package require Thread
proc printme {aa} {
puts "$aa"
}
set abc "dasdasdas"
set pool [tpool::create -maxworkers 4 ]
# The list of *scripts* to evaluate
set tasks {
{puts "ThisisOK"}
{puts $abc}
{printme "1234"}
}
# 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"
}
我总是得到: 执行错误206: invalid command name "printme"invalid command name "printme" 在执行时 "printme "1234"" 从内部调用 "tpool::get $pool $job"
为什么?
你的问题是,Tcl 线程模型与 C 语言中使用的模型非常不同。Tcl 的模型基本上是 'shared nothing by default' 主要基于消息传递的模型。
所以池中的每个线程都是一个独立的解释器,并且对 proc
printme 一无所知。你需要用你需要的过程来初始化这些解释器。
查看 ::tpool::create
命令的文档,它有一个选项可以提供一个 -initcmd
您可以在其中定义或 package require
您需要的东西。
所以试试这个来初始化你的线程:
set pool [tpool::create -maxworkers -initcmd {
proc printme {aa} {
puts "$aa"
}}]
https://www.tcl.tk/man/tcl/ThreadCmd/tpool.htm#M10
更详细地回答您的评论:
不,没有办法让 Tcl 线程像 C 线程一样工作并自由共享对象和过程。这是一个基本的设计决策,允许 Tcl 拥有一个没有大量全局锁的解释器(与例如 CPython 相比),因为大多数事情都是线程本地的并且使用线程本地存储。
但是有一些方法可以使多线程解释器的初始化和使用更容易。一个是 ::tpool::create
中的 -initcmd
参数,它允许您为池中的每个解释器 运行 初始化代码,而无需手动执行。如果您所有的代码都在一个包中,您只需添加一个 package require
并正确初始化您的解释器。
如果你真的想在多个线程之间共享状态,你可以使用::tsv
子命令。它允许您以明确的方式在线程之间共享数组和其他内容。但在幕后,它涉及您可能从 C 中了解到的典型锁和互斥锁来调解访问。
thread
包中还有另一组命令,可让您更轻松地进行初始化。这是 ttrace
命令,它允许您简单地 trace
在一个解释器中执行的内容并在另一个解释器中自动重复它。它非常聪明,只有 shares/copies 你真正用于目标的过程,而不是预先加载所有东西。