每个连接一个解释器/线程? [英] One interpreter/thread per connection?

查看:23
本文介绍了每个连接一个解释器/线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想编写一个服务器,人们可以在其中登录、发送/输入一些命令并退出.很多人可能同时连接,但我不想每个人都有很多状态变量,比如正在发送姓名"、正在发送密码"、正在上传命令的第二阶段"...为每个传入连接运行一次此脚本调用会容易得多:

I want to write a server where people log in, send/type some commands and log out. Many persons may be connected at the same time, but I don't want to have a lot of state variables for each person, like "is sending name", "is sending password", "is in the second stage of the upload command"... It would be much easier to run one invocation of this script for each incoming connection:

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 个连接,内存和速度是否合适?或者这就是你可以用线程做的事情?

Would memory and speed be OK with creating one interpreter per connection, even if there's about 50 connections? Or is this what you can do with threads?

推荐答案

一点点实验(观看使用系统工具的交互式会话)表明 Tcl 应用程序进程中的每个 Tcl 解释器,无需额外的用户命令,就可以在某个地方使用300kB 到 350kB 之间.除此之外,用户命令和脚本是额外的,堆栈帧也是如此(在解释器中运行任何东西都是必需的).相乘,您可能会为 50 个解释器上下文获得 17MB,任何现代计算机都可以处理而不会跳过任何节拍.请注意,口译员不允许同时执行.

A little bit of experimentation (watching an interactive session with system tools) indicates that each Tcl interpreter within a Tcl application process, with no additional user commands, takes somewhere between 300kB and 350kB. User commands and scripts are extra on top of that, as are stack frames (necessary to run anything in an interpreter). Multiplying up, you get maybe 17MB for 50 interpreter contexts, which any modern computer will handle without skipping a beat. Mind you, interpreters don't allow for simultaneous execution.

线程的权重更重,因为 Tcl 的线程模型让每个线程都有自己的主解释器(实际上所有解释器都严格绑定到单个线程,这是一种用于大大减少 Tcl 实现中全局锁数量的技术).因此,推荐的线程数将在很大程度上取决于部署硬件中可用 CPU 的数量以及您的代码受 CPU 限制而不是 IO 限制的程度.

Threads are heavier weight, as Tcl's thread model has each thread having its own master interpreter (and in fact all interpreters are strictly bound to a single thread, a technique used to greatly reduce the amount of global locks in Tcl's implementation). Because of this, the recommended number of threads will depend massively on the number of available CPUs in your deployment hardware and the degree to which your code is CPU bound as opposed to IO bound.

如果您可以使用 Tcl 8.6(8.6.0 在我编写本文时标记为在存储库中发布,但未发布),那么您可以使用 coroutines 对连接状态进行建模.它们比解释器,可用于进行某种协作的多任务处理:

If you can use Tcl 8.6 (8.6.0 is tagged for release in the repository as I write this, but not shipped) then you can use coroutines to model the connection state. They're much lighter weight than an interpreter, and can be used to do a sort of cooperative multitasking:

# 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 密集型处理并且需要注意保护登录安全(考虑使用 tls 包 以保护与 SSL 的连接.

This isn't suitable if you need to do CPU intensive processing and you need to be careful about securing logins (consider using the tls package to secure the connection with SSL).

这篇关于每个连接一个解释器/线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆