Асинхронные / синхронные одновременные вызовы с очередями - PullRequest
3 голосов
/ 08 апреля 2011

У меня есть сценарий, в котором я выполняю некоторую разновидность сообщений типа Actor-Model, где я хочу, чтобы метод вставлял задачу или делегировал в очередь (возможно, новый ConcurrentQueue), ждал, пока какой-то другой процесс обработает очередь, выполнить задачу, а затем вернуть результат, желательно без блокировки. Метод может быть вызван как синхронно, так и асинхронно. Одновременно может выполняться только одно действие в очереди

Я не могу обернуть голову, как сделать это несколько более производительным способом, пожалуйста, помогите:)

EDIT

Вот попытка, кто-нибудь видел какие-либо проблемы с этим подходом (исключая обработку исключений)? Кроме того, я могу себе представить, что это связано с большими накладными расходами по сравнению с простой блокировкой, и как это можно сравнить, например, с использованием асинхронных делегатов?

  public partial class Form1 : Form
  {
    private BlockingCollection<Task<int>> blockingCollection = new BlockingCollection<Task<int>>(new ConcurrentQueue<Task<int>>());
    private int i = 0;
    public Form1() {
      InitializeComponent();

      Task.Factory.StartNew(() =>
      {
          foreach (var task in blockingCollection.GetConsumingEnumerable()) {
            task.Start();
            task.Wait();        
          }
      });
    }


    public int Queue() {
      var task = new Task<int>(new Func<int>(DoSomething));
      this.blockingCollection.Add(task);
      task.Wait();
      return task.Result;
    }

    public int DoSomething() {
      return Interlocked.Increment(ref this.i);
    }

    private void button1_Click(object sender, EventArgs e) {
      Task.Factory.StartNew(() => Console.Write(this.Queue()));
    }


  }

1 Ответ

0 голосов
/ 08 апреля 2011

TPL должен сделать это за вас - просто наберите Wait() на вашем Task<T> - однако нет способа сделать это без блокировки;по определению, в вашем сценарии именно то, что вы хотите сделать .Блокировка может осуществляться через lock, но есть и другие способы - TPL скрывает это.Лично в аналогичном сценарии я делаю это с пользовательской очередью и мини-пулом объектов, которые можно использовать для блокировки (никогда не показывать за пределами оболочки).

Возможно, вы также захотите взглянуть на C # 5async / await stuff.

Но обратите внимание: если вы не собираетесь делать ничего полезного во время ожидания, вы можете также запустить этот код непосредственно в текущем потоке - если проблема не связана с потоком,например мультиплексор.Если вам интересно, позже сегодня (или в выходные дни) я намереваюсь выпустить мультиплексор, который использует stackoverflow для общения с redis, что (по крайней мере в синхронном режиме) имеет именно те проблемы, которые вы описываете.

КакПримечание;если вы можете работать с обратным вызовом (из другого потока) и не должны ждать по завершении, это может быть более эффективным в целом.Но это не подходит для каждого сценария.

...