除非我执行while循环并检查完整的布尔值

时间:2018-08-29 13:23:05

标签: c# asynchronous parallel-processing async-await task

我的函数将很快返回信息。这真是个好消息!但是,由于并行循环正在异步运行,因此该函数会在循环完成之前返回一个值,除非我在主线程上执行了一些长时间运行的任务以等待结果。没有用户界面,所以我正在使用async / await尝试在TPL中快速获得结果。

我引入了一个布尔标志值和while循环以等待结果。

这可行,但看起来很奇怪。

在我的特定情况下,是否有更好的方法来“等待”结果。 当我使用“ while循环”时,这似乎是第一个代码片段。

注意:我应该提到,因为这是一个Alexa响应,所以在此功能之外是一个任务,“ Task.Delays”持续八秒钟,然后返回响应,以防我的其他任务花很长时间并且Alexa打算超时。

private static string SavedImageAnalysisResult(IReadOnlyCollection<Image> savedImageList, ConfigurationDto config)
    {
        string result = "[]";
        BreakImageAnalysis = false;

        if (!savedImageList.Any()) return result;

        Parallel.ForEach(savedImageList, new ParallelOptions
        {
            MaxDegreeOfParallelism = 5000
        },
            async (image, loopState) =>
            {
                Task.Run(() => Console.Write("██"));

                string threadLocalAnalysisResult =
                    await AnalyzeImageAsync(image.ImageBytes, config);

                if (IsEmptyOrErrorAnalysis(threadLocalAnalysisResult)) return;
                Task.Run(() => Console.Write("█ █"));
                result = threadLocalAnalysisResult;
                BreakImageAnalysis = true;
                loopState.Break();
            });

        while (!BreakImageAnalysis) if (BreakImageAnalysis) break; //strange to do this?

        return result;
    }

此函数的调用方式如下:

public static List<Person> DetectPersonAsync()
    {
        Task.Run(() => Console.WriteLine("{0}\nNew Person Detection Requested...", DateTime.Now.ToString("f")));

        ConfigurationDto config = Configuration.GetSettings();

        camera = new SecurityCamera();

        byte[] imageData = camera.GetImageAsByte(config.SecurityCameraUrl +
                                                 config.SecurityCameraStaticImage +
                                                 DateTime.Now);

        if (!imageData.Any()) return null;

        string imageAnalysis = "[]";

        SavedImageList = camera.ImageCache;

        Task.Run(() => Console.WriteLine("\nBegin Image Analysis...\n"));

        var imageAnalysisTasks = new[]
        {
            Task.Factory.StartNew(() => SavedImageAnalysisResult(SavedImageList, config)),
            Task.Factory.StartNew(() => InProgressImageAnalysisResult(camera, config))
        };

        Task.WaitAll(imageAnalysisTasks);

        Task.Run(() => Console.WriteLine("\n\nAnalysis complete\n"));

        if (!IsEmptyOrErrorAnalysis(imageAnalysisTasks[0].Result))
            imageAnalysis = imageAnalysisTasks[0].Result;

        if (!IsEmptyOrErrorAnalysis(imageAnalysisTasks[1].Result))
            imageAnalysis = imageAnalysisTasks[1].Result;

        return !IsEmptyOrErrorAnalysis(imageAnalysis)
            ? JsonConvert.DeserializeObject<List<Person>>(imageAnalysis)
            : new List<Person>();
    }

但是此函数的调用方式如下:

  if (alexa.IsLaunchRequest(alexaRequest))
   {
    //We don't want to wait for these two tasks to return
    Task.Run(() => SendSecurityImageToMagicMirrorUi());
    Task.Run(() => alexa.PostDirectiveResponseAsync(alexaRequest));

     //On your marks get set go! 8 seconds and counting
            return await Task.WhenAny(new[]
           {

               Task.Run(() => GetAlexaCognitiveResponseAsync()),
               Task.Run(() => AlexaRequestTimeoutMonitor())

      }).Result;
     }

最后还有超时功能,如果8秒钟结束,它将返回:

 private static async Task<object> AlexaRequestTimeoutMonitor()
    {
        await Task.Delay(new TimeSpan(0, 0, 0, 8));

        return AlexaApi.ResponseBuilder(CreateNoPersonDetectionPhrase(new AlexaSynthesisResponseLibrary()), false);
    }

它在'CreateNoPersonDetectedPhrase'函数中,在其中我将'IsFound'布尔标志改回'false'

1 个答案:

答案 0 :(得分:1)

您的Parallel.ForEach启动异步委托,实际上它们正在并行执行,直到await AnalyzeImageAsync点返回Task作为承诺。现在有了这个承诺Parallel.ForEach“认为”此任务已完成,而实际上异步操作很可能才刚刚开始。但是没有人在等待,Parallel.ForEach很快就完成了。因此,您需要在Parallel.ForEach循环之外公开这些承诺,以便例如可以使用Task.WhenAll等待它们。

但是我也建议考虑是否完全需要这种并行化,因为如果大多数AnalyzeImageAsync操作(此处未介绍)不是CPU限制的,则仅使用异步性更为合理

等待Parallels.Forxxx中的异步任务的最简单方法(我并不是说最好的)

    public static async Task SomeAsyncTask()
    {
        await Task.Delay(5000);
        Console.WriteLine("2222");
    }

    public static async Task Loop()
    {
        var collection = new[] { 1, 2, 3, 4 };
        var asyncTasks = new Task[4];

        Parallel.ForEach(collection,
            (item, loop, index) =>
            {
                Console.WriteLine("1111");
                asyncTasks[index] = SomeAsyncTask();
            });

        await Task.WhenAll(asyncTasks);
    }

请注意,SomeAsyncTask()之后的所有内容都应移到任务的继续中(在本例中为Console.WriteLine("2222"))。