在Rust中分配工作人员

时间:2014-10-19 14:26:28

标签: rust

use std::iter;

fn worker_sum(from: u64, to: u64) -> u64 {
    range(from, to).fold(0u64, |sum, x| sum + x)
}

fn main() {
    let max = 5u64;
    let step = 2u64;

    let (sender, receiver) = channel::<u64>();
    for x in iter::range_step_inclusive(0u64, max, step) {
        let end = if x + step > max { max } else { x + step };
        //println!("{} -> {} = {}", x, end, worker_sum(x, end));
        let local_sender = sender.clone();
        spawn(proc(){
            local_sender.send(worker_sum(x, end));
        });
    }
    loop {
        match receiver.try_recv() {
            Ok(x) => println!("{}", x),
            Err(_) => break,
        }
    }
}

我收到错误:

  

任务''在关闭频道发送'失败',/ home / runbuild / src / hub-buildbot / slav / nightly-linux / build / src / libsync / comm / mod.rs:573

我以某种方式了解问题,但如何正确地从频道“选择”?虽然我正在使用每晚构建,但据说这些文档已经改进了文档(从版本0.13开始),因此文档非常稀疏。

所以我的问题是:

  1. 如何通过尽可能少的代码结构更改来解决问题?
  2. 如何使代码惯用?

1 个答案:

答案 0 :(得分:3)

您遇到的问题是,在发送所有数据之前,通道会被读取任务关闭。你的循环是:

loop {
    match receiver.try_recv() {
        Ok(x) => println!("{}", x),
        Err(_) => break,
    }
}

在此循环中,您的接收器会在遇到错误时立即中断。一旦循环中断,您的函数将到达其范围的末尾,接收器将被销毁。完成此操作后,任何发送更多数据的尝试都将失败。

问题在于,您的收件人会收到Err(Empty),因为发件人尚未发送任何内容。您必须等待它们,并且只有在遇到Err(Disconnected)

时才会中断

您需要将代码更改为此类代码(注释中的说明):

use std::iter;

fn worker_sum(from: u64, to: u64) -> u64 {
    range(from, to).fold(0u64, |sum, x| sum + x)
}

fn main() {
    let max = 5u64;
    let step = 2u64;

    let (sender, receiver) = channel::<u64>();

    for x in iter::range_step_inclusive(0u64, max, step) {
        let end = if x + step > max { max } else { x + step };
        // here, each thread will own its own sender, and the channel will
        // be closed once all senders are destroyed.
        let local_sender = sender.clone();
        spawn(proc(){
            local_sender.send(worker_sum(x, end));
            // Once we reach here, the sender of this task is destroyed.
        });
    }

    // We destroy the sender of the main task,
    // because we don't want to wait for it:
    // it would deadlock the program
    drop(sender);

    loop {
        match receiver.try_recv() {
            Ok(x) => println!("{}", x),
            // We break only if the channel is closed,
            // it means that all senders are finished.
            Err(e) if e == ::std::comm::Disconnected => { break; },
            _ => {}
        }
    }
}