Tpl实施问题

时间:2017-10-16 15:18:24

标签: c# c#-4.0 async-await task-parallel-library webclient

Tpl Sample Click here to download

你好, 我正在尝试在我的项目中实现tpl。我使用Web客户端创建了5个并行HTTP调用。

我想要实现的目标。 如果5个并行调用中的任何一个返回包含" First"然后杀死休息电话并继续接听电话"第一个"

我尝试了什么:

我上面附上了示例代码。我使用了以下Predicate函数。

async Task<T> WhenAny<T>(IEnumerable<Task<T>> tasks, Func<T, bool> predicate)
    {
        var taskList = tasks.ToList();
        Task<T> completedTask = null;
        do
        {
            completedTask = await Task.WhenAny(taskList);
            taskList.Remove(completedTask);
        } while (!predicate(await completedTask) && taskList.Any());

        return completedTask == null ? default(T) : await completedTask;
    }

并将其称为如下:

 public async Task<string> methodname()
    {
        string sUrl = "https://abcd.com/test.php";
        Task<string> task1 = DownLoadData(sUrl);
        Task<string> task2 = DownLoadData(sUrl);
        Task<string> task3 = DownLoadData(sUrl);
        Task<string> task4 = DownLoadData(sUrl);
        Task<string> task5 = DownLoadData(sUrl); 
        var tasks = new[] { task1, task2, task3, task4, task5 };
        await WhenAny(tasks, t => t.Contains("First"));

        return "";


    }

但它没有达到标准。请建议我遗漏的地方。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:2)

我假设您有一个要检查的网址列表,而不是重复检查相同的网址(?!),但在任何情况下都可以使用相同的方法....

我喜欢使用TPL Dataflow来做这类事情。它允许您将多个异步操作(例如,下载字符串)与多个同步操作(例如检查子字符串的内容&#34; First&#34;)链接在一起,并提供各种类型的“旋钮”。调整控制并行度,缓冲区大小等。我们还可以传递取消令牌以取消进一步处理。首先,让我们创建一个取消令牌源:

var cancellationSource = new CancellationTokenSource();

现在,我们的第一个&#39;块&#39;将是TransformBlock<string,string>。这个区块的工作就是采取网址字符串和“转换”字符串。通过调用DownloadData函数将其转换为内容字符串:

var downloadBlock = new TransformBlock<string,string>(
        async s => await DownloadData(s), 
        new ExecutionDataflowBlockOptions
        {
            MaxDegreeOfParallelism = 10, //allow up to 10 simulteneous downloads
            BoundedCapacity = 100,       //allow the block to store up to 100 urls in a buffer
            CancellationToken = cancellationSource.Token 
        });

第二个块将是TransformMany<string,string>块。这种类型的块允许我们将字符串转换为字符串集合。我们只是通过返回一个空集合来过滤掉任何不符合我们标准的内容字符串:

    var filterBlock = new TransformManyBlock<string,string>(
        s => {
                if (s.Contains("First")) 
                {
                    return new string[]{s};
                } else 
                {
                    return new string[]{};
                }
            }); // (we could also pass a cancellation token here)

最后一个区块是您使用找到的内容字符串执行某些操作(即您找到的第一个下载的内容包含&#34; First&#34;)。我们还Cancel()我们的取消令牌来源,以防止我们在找到满足我们标准的会议后开始处理任何新网址:

var finalBlock = new ActionBlock<string>(
        s => {
                cancellationSource.Cancel();
                //do whatever you want with the content string here            
            });

我们现在需要做的就是加入块并输入网址:

downloadBlock.LinkTo(
    filterBlock,
    new DataflowLinkOptions
    {
        PropagateCompletion = true // this flag ensures that if the first block completes ALL urls it signals to the nect block that no more will come
    }
);
filterBlock.LinkTo(
    finalBlock,
    new DataflowLinkOptions
    {
        PropagateCompletion = true,
        MaxMessages = 1         //we are only interested in the first message that arrives in our final block
    });

downloadBlock.Post("http://url.com/blah1");
downloadBlock.Post("http://url.com/blah2");
// etc...

downloadBlock.Complete(); // this signals that we've ran out of Urls to process
finalBlock.Completion.Wait(); //now wait for any messages we have 'in progress' to work through the pipeline