2014-10-19 37 views
0
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, 
     } 
    } 
} 

我得到的錯誤:分發跨工人工作鏽

task '' failed at 'sending on a closed channel', /home/rustbuild/src/rust-buildbot/slave/nightly-linux/build/src/libsync/comm/mod.rs:573

不知何故,我明白的問題,而是如何正確地從通道「選擇」?雖然我使用的是nightly build,但據說這樣可以改進文檔(自0.13版本開始),但文檔卻非常稀少。

所以我的問題是:

  1. 如何與代碼中儘可能少的結構變化解決這個問題?
  2. 如何使代碼習慣?

回答

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; }, 
      _ => {} 
     } 
    } 
}