【问题标题】:Multiple async call多个异步调用
【发布时间】:2012-12-21 22:46:27
【问题描述】:

我需要创建多个异步调用,例如

IList<Task> Ts = new List<Task>();
Ts.Add(GetInformationFromServer(ID));

但我没有在线程中等待,我是从

所以应该可以这样做(旧方法之一,但有新方法吗?),来自另一个调用

GetInformation(string ID) {
   while (!Finish) {
      Thread.Sleep(100);
   }
   return _Information.First(a=>a.ID==ID);
 }

我当然可以将任务保存在一个变量中,但是如何启动它们呢?我如何获得状态?
我想我可以在另一个线程中等待它们,但是如何检查它们是否完成?我应该自己实施吗?
以及如何启动它们(我应该只使用 Task.WhenAll 而不等待)?

更新

我想通了,我必须实现自己的方式,所以答案是这样的,但我需要使用Task而不是Func

/// The executed elements
private IList<T> _ExecutedElements;

/// The Stack over the elements to be executed
private Stack<T> _ExecutingElements;

/// The method to be runned
private Func<object, Task<T>> _Method;

/// Should the while-loop start?
private bool _Running;

/// The Task
private Task<T> _Task;

/// Construct the class
/// <param name="Method">The function to be executed</param>
public MultiAsync(Func<object, T> Method) {
   _Method = Method;
}

/// Add an element
/// <param name="Item">The item to be added</param>
public void AddItem(T Element) {
   _ExecutingElements.Push(Element);
}

/// Execute the method
public async void ExecuteAsync() {

   // Set it to start running
   _Running = true;

   // While there are elements left
   while (_ExecutingElements.Count > 0) {

      // Check if it is not running, and if it isn't break out
      if (!_Running) { break; }

      // The current element
      T Element = default(T);

      // Pop out the element, that has not been runned through
      do { Element = _ExecutingElements.Pop(); }
      while (!_ExecutedElements.Contains(Element));

      // Check if there is an element, and if there is execute the method and await it
      if (Element != default(T)) {
         await ExecuteMethodAsync(Element);
      }
   }
}

/// Execute the item
/// <param name="Item">The item to be executed</param>
/// <returns>The executed item (due to reflection in FillInformation, the Item is filled)</returns>
public async Task<T> ExecuteItemAsync(T Item) {

   // Check if the item has not been executed, and if it is not executed
   if (!_ExecutedElements.Contains(Item)) {

      // Stop the while-loop
      _Running = false;

      // Check if the Task is running, and if it is await it
      if (_Task != default(Task) && !_Task.IsCompleted && !_Task.IsFaulted) {
         await _Task;
      }

      // Execute the method using the specific item
      await ExecuteMethodAsync(Item);
   }

   // Start the while-loop
   ExecuteAsync();

   // Return the element
   return Item;
}

/// Execute the method
/// <param name="Item">The item to run</param>
/// <returns>The Task to be executed</returns>
private async Task ExecuteMethodAsync(T Item) {

   // Set the Task
   _Task = _Method.Invoke(Item)

   // Start the task
   T Element = await _Task;

   // Add the item to the List
   _ExecutedElements.Add(Element);

   // Fill the information
   FillInformation(Element);
}

通话是这样的

private async void FillTasksAsync(IEnumerable<Model.Task> Tasks) {
   _InfoLoader = new MultiAsync<Model.Task>(Tsk => { return GetTaskAsync(Tsk); });

   foreach (var Tsk in Tasks) {
      _InfoLoader.AddItem(Tsk);
   }
}

【问题讨论】:

  • 你能描述更多关于你的问题吗?您是否使用多个任务来拆分问题?线程是否需要在某些状态下同步?一般来说,最好不要在后台线程中休眠,而是等到工作准备好后再启动任务。
  • 是的,我正在使用异步调用来解决问题。而且它们不会同步,因为它们正在处理不同的对象。我也许可以使用 Threads 或 ThreadPool,然后加入它们以便在它们准备好时收到通知
  • 你为什么不想await?使用await 是最干净且最受支持的解决方案。
  • 因为我当时不需要它,但是如果用户选择列表中的项目,信息应该会快速显示,所以我想在后台下载它

标签: c# async-await


【解决方案1】:

我有一篇博客文章讨论了asynchronous initialization,这听起来像是您需要的。它源自 Stephen Toub 的一个原创想法。

在这种情况下,您可以使用:

List<AsyncLazy<string>> Ts = ...
Ts.Add(new AsyncLazy<string>(() => GetServerStringAsync(ID));

要开始一次下载,您可以:

Ts[0].Start();

当你需要它时,你可以这样做:

var result = await Ts[0];

如果尚未完成下载,它将(异步)等待它完成下载。如果已经有,那么您将立即得到结果。

【讨论】:

  • 所以我需要将所有项目添加到列表中,然后全部使用 start 还是?我想,我可以做一次,但后来我想我应该实现我自己的类,这一定是结果。我在想一件事,也许您有权回答这个问题:Task.WhenAll 是一次执行一个还是多次执行?
  • 你需要开始每一个。 Task.WhenAll 不同;它返回一个Task,它在传递给它的所有任务都完成后完成。
  • 好的,所以它将所有任务合并为一个?
    如果明天没有人提出更好的答案,我认为我最好创建自己的课程,然后我需要一些回应以提高性能
  • 它返回一个Task,它在传递给它的所有任务都完成后完成。您可以将其视为一种“组合”。 AsyncLazy 对你不起作用有什么原因吗?
  • 我认为你应该在每个任务完成时调用 start-method
猜你喜欢
  • 2019-10-05
  • 1970-01-01
  • 2015-05-10
  • 2017-09-17
  • 2011-03-18
  • 2017-11-06
  • 2013-08-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多