多个异步任务执行

本文关键字:执行 任务 异步 | 更新日期: 2023-09-27 18:01:11

请耐心等待:-(

我正在为c#中的TPL而挣扎,一直在努力找出设计一个解决方案的最佳方法,以启动多个异步任务,等待它们完成,然后继续前进。我的初始POC如下。每个IDataGatherer实例都需要获取数据并将其传递到DataObject实例中。

  1. 我不确定如何处理DownloadStringTaskAsync调用的延续,这样我就可以获得结果并将其传递到DataObject中。ContinueWith希望提供一个具有void返回签名的方法,但我觉得ExtractData方法需要返回一个Task实例,否则我没有从GetDataAsync((方法返回的Task实例。

  2. 我还想知道我是否需要在我的IDataGatherer实例中引入TaskCompletionSource,但我如何将其与正在进行实际工作的任务联系起来——例如DownloadstringTaskAsync和ExtractData?

interface IDataGatherer
{
    Task<DataObject> GetDataAsync();
}
class DataObject
{
    public string Data { get; set; }
}
class IpGatherer : IDataGatherer
{
    private readonly string _url = "http://ip.jsontest.com";
    public Task<DataObject> GetDataAsync()
    {
        var tcs = new TaskCompletionSource<DataObject>(); // Do I need this???
        var client = new WebClient();
        // stuck here
        var task = client.DownloadStringTaskAsync(_url).ContinueWith(ExtractData);
    }
    private void ExtractData(Task<string> obj)
    {
    }
}
class Program
{
    private static void Main(string[] args)
    {
        // takes a list of IDataGatherers and waits for them
        // all to complete, handles exceptions, etc.
    }
}

以这种方式设计解决方案可能会使事情过于复杂,所以我愿意接受清理或更简洁的建议。

我使用的是.NET 4.5

多个异步任务执行

首先,您不需要TaskCompletionSource。这是因为ContinueWith()可以提供一个具有非void签名的方法。例如:

public Task<DataObject> GetDataAsync()
{
    var client = new WebClient();
    return client.DownloadStringTaskAsync(_url)
                 .ContinueWith((Func<Task<string>, DataObject>)ExtractData);
}
private DataObject ExtractData(Task<string> task)
{
    return new DataObject(task.Result);
}

(使用Result不会阻塞,因为您可以确定Task将在此时完成。(

但由于您使用的是DownloadStringTaskAsync(),因此您可能使用的是.Net 4.5,这意味着您可以使用await。这使得代码更加简单:

public async Task<DataObject> GetDataAsync()
{
    var client = new WebClient();
    var s = await client.DownloadStringTaskAsync(_url);
    return ExtractData(s);
}
private DataObject ExtractData(string s)
{
    return new DataObject(s);
}