2008-05-21

一种有趣的编程模型

Views: 11160 | 1 Comment

假设我们从某处接收命令, 一次只能接收一个. 如果命令为 1, 我们只要祈祷, 就可以得到金钱. 如果命令为 2, 那么我们必须到外面 ATM 机取钱, 然后放入钱包.

这个模型可以用下面的计算机伪代码描述:

while(cmd = read_cmd()){
    switch(cmd){
        case 1:
            m = pray();
            wallet.put(m);
            break;
        case 2:
            m = get_money_from_atm();
            wallet.put(m);
            break;
    }
}

从直觉可以知道, get_money_from_atm() 耗时可能达到 1 个小时, 但是 pray() 只需要几秒. 上面的程序是线性的, 所以 get_money_from_atm() 会影响我们接收新的命令, 从而影响我们的钱包快速的增加. 这是一个严重的问题! 下面将讨论如何解决这个问题.

我们可以委托其他人帮我们去 ATM 机取钱. 所以,

m = get_money_from_atm();
wallet.put(m);

可以改为

delegate(){
    m = get_money_from_atm();
    wallet.put(m);
}

delegate 代码段中的代码会立即被加入到异步执行队列中(在计算机中常常由其它的线程处理这个队列), 所以我们又可以去接收命令了.

问题是, wallet.put() 不是线程安全的, 所以, 调用它时必须加锁. 所以代码应该是

delegate(){
    m = get_money_from_atm();
    lock(wallet){
        wallet.put(m);
    }
}
wallet.put(m);

也要修改为

lock(wallet){
    wallet.put(m);
}

最终的代码是

while(cmd = read_cmd()){
    switch(cmd){
        case 1:
            m = pray();
            lock(wallet){
                wallet.put(m);
            }
            break;
        case 2:
            // 这段代码交给另一个线程执行, 所以它几乎不消耗当前线程的时间.
            delegate(){
                m = get_money_from_atm();
                lock(wallet){
                    wallet.put(m);
                }
            }
            break;
    }
}

这里还有很大的改进空间, case 1 情况比 case 2 出现的机率大得多, 很多时候并没有其它的线程争用 wallet, 但我们还是对它进行加锁, 这些加锁都是无谓的. 我想, 能不能达到下面的效果:

while(cmd = read_cmd()){
    switch(cmd){
        case 1:
            m = pray();
            wallet.put(m);
            break;
        case 2:
            delegate(){
                // 将本代码块中的代码委托给其它线程执行.
                m = get_money_from_atm();
            }then{
                // 这里的代码会在委托提交后执行.
                continue;
            }onexit{
                // 一旦委托的代码执行完毕, 会跳到这里继续执行.
                wallet.put(m);
            }// 这段几乎不会消耗当前线程的时间.
            break;
    }
}

委托调用立即返回, 但是, 一旦委托过程处理完毕, 代码又被插入原来的地方继续执行. 也就是说, 一旦 get_money_from_atm() 在另一个线程中执行, 便会产生一个中断, 并执行 onexit 代码段. 当然, 这个中断的级别不能高到中断其它代码的执行, 如 pray().

有一个可以改进的地方, 就是我们不希望委托的数量过多, 所以为 delegate 增加一个参数, delegate(maxwait=2), 表示如果有 2 个执行中的委托, 便阻塞当前的线程.

Related posts:

  1. C/C++ 语言 switch-case 后面的花括号
  2. PHP 解码 C 字符串
  3. PHP的continue 2
  4. Redis 导数据的 PHP 脚本
  5. LevelDB Seek() 特别慢的场景
Posted by ideawu at 2008-05-21 19:02:27

One Response to "一种有趣的编程模型"

  • 异想天开吧!既然有多线程,“回到原来的地方”从何说起?中断返回?那是阻塞,实际成了单线程了;找机会插进去?那还得面对锁的问题,不然完整性没保证。 Reply

Leave a Comment