When you invoke `OnCompleted()` on a C# task awaiter, how do you wait on the new job given inside the OnCompleted call?

时间:2015-10-23 19:18:29

标签: c# multithreading

My Controller object makes calls to a MySQL DB over SSH using Renci.SshNet, since i am connecting to several DB, i turned to multithreading, the function af.FetchAll() return a DataSet, all of which are added to a list DataList<DataSet>, i then ask all tasks to complete, then i will give my DataList to writer object to save it to CSV file, The problem is: The code inside the awaiter.OnCompleted(() =>..etc is still updating the DataList while the file writer is trying to access it, despite me asking the task to complete foreach (Task t in taskList) t.Wait(); , how can i make sure that the awaiter finished executing before i go on and write the 'DataList' to file

    public void Query()
    {
        List<QueryValue> QueriesList = quryValLister.GetQueriesList();
        List<ConnectionValues> ConnectionsList = concValLister.GetConnectionList();
        // iterating over servers 
        List<Task> taskList = new List<Task>();
        foreach (ConnectionValues obj in ConnectionsList)
        {
            Controller af = new Controller(obj, QueriesList);
            Task<DataSet> taskDataResult = Task.Run (() => af.FetchAll());
            taskList.Add(taskDataResult);
            var awaiter = taskDataResult.GetAwaiter();
            awaiter.OnCompleted(() =>
            {
                DataSet temp = awaiter.GetResult();
                if (temp != null)
                {
                    MyDataList.Add(temp);
                }

            });
        }
        foreach (Task t in taskList) t.Wait();
    }

1 个答案:

答案 0 :(得分:6)

您不应该在常规代码中使用GetAwaiter

如果你想异步写这个,你可以这样做:

public Task QueryAsync()
{
  List<QueryValue> QueriesList = quryValLister.GetQueriesList();
  List<ConnectionValues> ConnectionsList = concValLister.GetConnectionList();
  // iterating over servers 
  var tasks = ConnectionsList
      .Select(obj => Task.Run(() => new Controller(obj, QueriesList).FetchAll()));
  MyDataList.AddRange(await Task.WhenAll(tasks));
}

或者,如果你想同步写它:

public void Query()
{
  List<QueryValue> QueriesList = quryValLister.GetQueriesList();
  List<ConnectionValues> ConnectionsList = concValLister.GetConnectionList();
  // iterating over servers 
  var tasks = ConnectionsList
      .Select(obj => Task.Run(() => new Controller(obj, QueriesList).FetchAll()))
      .ToArray();
  Task.WaitAll(tasks);
  foreach (var task in tasks)
    MyDataList.Add(task.Result);
}

请注意,同步版本中的错误处理方式不同;异常包含在AggregateException