Tcl 每个连接一个解释器/线程?

Tcl 每个连接一个解释器/线程?,tcl,Tcl,我想写一个服务器,让人们登录,发送/键入一些命令,然后注销。很多人可能同时连接,但我不想为每个人设置很多状态变量,比如“正在发送姓名”、“正在发送密码”、“正在上传命令的第二阶段”。。。为每个传入连接运行一次此脚本调用会容易得多: puts -nonewline $out "login: " gets $in login ;# check for EOF puts -nonewline $out "password: " gets $in password ;# check for EOF wh

我想写一个服务器,让人们登录,发送/键入一些命令,然后注销。很多人可能同时连接,但我不想为每个人设置很多状态变量,比如“正在发送姓名”、“正在发送密码”、“正在上传命令的第二阶段”。。。为每个传入连接运行一次此脚本调用会容易得多:

puts -nonewline $out "login: "
gets $in login ;# check for EOF
puts -nonewline $out "password: "
gets $in password ;# check for EOF
while {[gets $in command] >= 0} {
  switch -- $command {
    ...
  }
}

如果每个连接创建一个解释器,即使有大约50个连接,内存和速度还可以吗?或者这就是你可以用线程做的吗?

一点实验(用系统工具观看交互式会话)表明,Tcl应用程序进程中的每个Tcl解释器,不需要额外的用户命令,占用300kB到350kB的空间。除此之外,用户命令和脚本还有堆栈帧(在解释器中运行任何东西都需要)。乘以50个解释器上下文,你可能会得到17MB,任何现代计算机都可以毫不犹豫地处理这些上下文。请注意,口译员不允许同时执行

线程的重量更重,因为Tcl的线程模型让每个线程都有自己的主解释器(事实上,所有解释器都严格绑定到一个线程,这是一种用于大大减少Tcl实现中全局锁数量的技术)。因此,建议的线程数量在很大程度上取决于部署硬件中可用CPU的数量以及代码受CPU约束而非IO约束的程度


如果您可以使用Tcl 8.6(在我写这篇文章时,8.6.0在存储库中被标记为要发布,但没有发布),那么您可以使用来建模连接状态。它们的重量比口译员轻得多,可以用来进行某种协作式多任务处理:

# Your code, with [co_gets] (defined below) instead of [gets]
proc interaction_body {in out} {
    try {
        puts -nonewline $out "login: "
        co_gets $in login ;# check for EOF
        puts -nonewline $out "password: "
        co_gets $in password ;# check for EOF
        if {![check_login $login $password]} {
            # Login failed; go away...
            return
        }
        while {[co_gets $in command] >= 0} {
          switch -- $command {
            ...
          }
        }
    } finally {
        close $in
    }
}

# A coroutine-aware [gets] equivalent. Doesn't handle the full [gets] syntax
# because I'm lazy and only wrote the critical bits.
proc co_gets {channel varName} {
    upvar 1 $varName var
    fileevent $channel readable [info coroutine]
    while 1 {
        set n [gets $channel var]
        if {$n >= 0 || ![fblocked $channel]} {
            fileevent $channel readable {}
            return $n
        }
        yield
    }
}
# Create the coroutine wrapper and set up the channels
proc interaction {sock addr port} {
    # Log connection by ${addr}:${port} here?
    fconfigure $sock -blocking 0 -buffering none
    coroutine interaction_$sock interaction_body $sock $sock
}

# Usual tricks for running a server in Tcl
socket -server interaction 12345;  # Hey, that port has the same number as my luggage!
vwait forever

如果您需要进行CPU密集型处理,并且需要小心保护登录(考虑使用来保护与SSL的连接)。

如果标记已完成,我希望8.6.0今天或最晚明天发布。我们已经让它运行服务器很多年了,所以我们非常确定它是一个针对这类事情的健壮版本;我应该检查一下我的留言。目标是在12月20日之前。非常感谢。现在我明白了,合作项目似乎很棒。使用多个堆栈而不是一个堆栈,可以获得新的可能性维度。我的代码将无法访问一个或两个以上的CPU,因此我将跳过创建更多线程并节省一些编码时间。