簡體   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