繁体   English   中英

如何使用任务并行库执行多个任务并在第一个任务之后返回以实际返回数据

[英]How do I execute multiple Tasks using Task Parallel Library and return after the first one to actually return data

我正在开发一个应用程序,在该应用程序中,尽快将数据返回串行过程很重要,但是可以有多个来源来获取数据。 同样,有时一个来源要比另一个来源快,但您不知道将是哪个来源。 我正在使用ContinueWhenAny(...)。Wait()等待第一个Task结束,以便继续并退出调用方法。 但是,我需要先检查数据的有效性,然后才返回(或者如果所有任务都已完成并且它们都没有有效数据)。 现在,如果那是最先完成的任务,我的代码甚至会返回无效数据。

是否有一种方法可以执行类似“ ContinueWhenAny”的操作,但是只能在Task.Result满足特定条件时执行,否则请等待下一个任务等,直到最后一个任务完成为止。

同样,我需要确保一个结果有效后,其他线程才能取消。 这部分已经可以正常工作了。

当前,我的代码看起来像这样(剥离了异常处理,只是细节):

        ResultObject result = null;
        var tokenSource = new CancellationTokenSource();
        var tasks = listOfSources
                .Select(i => Task.Factory.StartNew(
                    () =>
                        {
                            i.CancellationToken = tokenSource.Token;
                            //Database Call
                            return i.getData(inputparameters);
                        }, tokenSource.Token));

        Task.Factory.ContinueWhenAny(
                tasks.ToArray(),
                firstCompleted =>
                    {
                        //This is the "result" I need to validate before setting and canceling the other threads
                        result = firstCompleted.Result;
                        tokenSource.Cancel();
                    }).Wait();
        return result;

有任何想法吗? 我不想使用ContinueWhenAll,因为如果第一次调用花费2秒,第二次调用花费10秒,那么如果第一次调用返回有效数据,我想在2秒内返回串行过程,否则请等待10秒,希望结果包含有效数据,并且仅在所有任务均已完成并且返回无效结果时才返回无效数据。

---------更新----感谢zmbq的好主意。 更新后的(工作)代码在下面,并且满足我的所有要求。 请注意,此代码与先前的代码之间的区别在于,如果没有一个Task产生有效结果,则此代码将返回空结果,而不是先前的代码本身返回无效结果。 更改此版本也不难,但是出于我的目的,我很满意在这种情况下返回null。

        ResultObject result = null;
        var tokenSource = new CancellationTokenSource();
        var tasks = listOfSources
                .Select(i => Task.Factory.StartNew(
                    () =>
                        {
                            i.CancellationToken = tokenSource.Token;
                            //Database Call
                            return i.getData(inputparameters);
                        }, tokenSource.Token)).ToArray();

        result = GetFirstValidResult(tokenSource,tasks);

        return result;


   private ResultObject GetFirstValidResult(CancellationTokenSource tokenSource, Task<ResultObject>[] tasks)
    {
        ResultObject result = null;
        Task.Factory.ContinueWhenAny(
            tasks,
            firstCompleted =>
                {
                    var testResult = firstCompleted.Result;
                    if(testResult != null && testResult.IsValid())
                    {
                        result = testResult;
                        tokenSource.Cancel();
                    }
                    else
                    {
                        var remainingTasks = tasks.Except(new[]{firstCompleted}).ToArray();
                        if(remainingTasks.Any())
                        {
                            result = GetFirstValidResult(tokenSource, remainingTasks);
                        } 
                    }
                }).Wait();
        return result;
    }

好吧,如果您的firstCompleted回调函数将检查结果,并在其余任务上调用ContinueWhenAny,以防结果不合法,那么您就可以完成。

与往常一样,我建议您看一下ZeroMQ 触发任务,并让每个任务将消息写入输出队列(如果结果合法)。 主线程将阻塞队列,并在收到有效消息或所有任务已经完成时返回。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM