Concurrency 阻止任务,直到队列中不为空

Concurrency 阻止任务,直到队列中不为空,concurrency,rust,Concurrency,Rust,我需要在一组任务之间分派作业。足够解决这个问题,但是如果队列为空,我需要阻止任务 以下代码(a中提供)是如何使用std::sync::deque的工作示例: extern crate time; use std::io::timer::sleep; use std::sync::deque::{BufferPool, Empty, Abort, Data}; use std::time::Duration; fn main() { let start = time::precise_t

我需要在一组任务之间分派作业。足够解决这个问题,但是如果队列为空,我需要阻止任务

以下代码(a中提供)是如何使用
std::sync::deque
的工作示例:

extern crate time;

use std::io::timer::sleep;
use std::sync::deque::{BufferPool, Empty, Abort, Data};
use std::time::Duration;

fn main() {

  let start = time::precise_time_s();
  let pool = BufferPool::new();
  let (worker, stealer) = pool.deque();

  for task_id in range(1i, 5) {
    let sc = stealer.clone();
    spawn(proc() {
      loop {
        let elapse = time::precise_time_s() - start;
        match sc.steal() {
          Empty      => { println!("[{} @ {:#7.4}] No items", task_id, elapse); sleep(Duration::milliseconds(300)) },
          Abort      =>   println!("[{} @ {:#7.4}] ABORT. Retrying.", task_id, elapse),
          Data(item) =>   println!("[{} @ {:#7.4}] Found {}", task_id, elapse, item)
        }
      }
    });
  }

  for item in range(1i, 1000) {
    for n in range(1i, 20) {
      worker.push(item * n);
    }
    sleep(Duration::milliseconds(1000));
  }

}
我看到有一个线程,但它会将作业发送到一个任务,即使该线程正忙于一个较旧的作业


我的问题是:在队列中有任何项目之前阻止任务的最佳方法是什么?

可能的解决方案是使用信号量:

extern crate time;

use std::io::timer::sleep;
use std::sync::deque::{BufferPool, Empty, Abort, Data};
use std::sync::{Semaphore, Arc};
use std::time::Duration;

fn main() {

  let start = time::precise_time_s();
  let pool = BufferPool::new();
  let (worker, stealer) = pool.deque();
  let sem = Arc::new(Semaphore::new(0));

  for task_id in range(1i, 5) {
    let sc = stealer.clone();
    let s = sem.clone();
    spawn(proc() {
      loop {
        let elapse = time::precise_time_s() - start;
        s.acquire();
        match sc.steal() {
          Empty      => {
              println!("[{} @ {:#7.4}] No items", task_id, elapse);
              sleep(Duration::milliseconds(300))
          },
          Abort      =>   {
              println!("[{} @ {:#7.4}] ABORT. Retrying.", task_id, elapse);
              s.release();
          },
          Data(item) =>   println!("[{} @ {:#7.4}] Found {}", task_id, elapse, item)
        }
      }
    });
  }

  for item in range(1i, 1000) {
    for n in range(1i, 20) {
      worker.push(item * n);
      sem.release();
    }
    sleep(Duration::milliseconds(1000));
  }

}
正如您在这里看到的,您在生成的每个值上释放一个信号量资源,并在从队列中获取值之前获取它。在这种情况下,返回的值永远不会为空,但仍然可以中止,并且您必须释放资源,因为没有读取任何内容,但该值仍在队列中


另一种可能的解决方案是使用通道,当没有您想要的值时,通道会阻塞。对于性能,您必须对这两种解决方案进行基准测试。

谢谢!最后,我为所有工作人员使用了一个全局信号量,这对于每个作业都是
release()
。代码在@Ayose中:您忘记在中止上释放资源。这样,当任务阻塞时,您将为队列中的每个中止保留一个值。或者在循环中调用
steal()
,直到获得数据。您是对的。谢谢你的评论!我为这个问题更新了gist,使用
循环来包装
steal()
。在中可以看到差异