当前位置: 首页 > 知识库问答 >
问题:

使用没有任何'await'运算符的task.waitall导致警告CS1998此异步方法缺少'await'运算符,将同步运行

凤棋
2023-03-14

我猜我的代码有很多薄弱点,所以请随时分享任何想法。顺便问一下,我的主要问题是,当我尝试执行以下操作时,以及在最后,当我希望等待所有任务(通过使用task.waitall)完成以检查是否存在任何异常时,是否真的会因为缺少'await'操作符而使代码的任何部分同步运行?

public class Program
    {
        static bool mock = true;
        static readonly object s_lockSource = new object();
        static readonly CancellationTokenSource s_tokenSource = new CancellationTokenSource();
        static readonly CancellationToken s_token = s_tokenSource.Token;
        public static async Task Main()
        {
            var sw = new Stopwatch();
            sw.Start();

            IConfigurationRoot config = new ConfigurationBuilder()
                .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
                .AddJsonFile("appsettings.json").Build();

            var logger = new LiteLogger(new MemoryStream(), config);
            logger.Log(LogLevel.Debug, "Fetching data...");

            var jsonHelper = new JsonHelper();
            IAsyncIO fileService = mock ? new MockAsyncIO() : new FileService(config, s_token);
            IAsyncService webService = mock ? new MockAsyncIO() : new WebService(config, s_token);

            var remoteFetchTask = webService.FetchAsync(InOutOptions.None);
            var localFetchTask = fileService.FetchAsync(InOutOptions.ForecastPath);
            var todaysFetchTask = fileService.FetchAsync(InOutOptions.TodaysPath);

            var parseRemoteDataTask = remoteFetchTask
                .ContinueWith(task =>
                {
                    lock (s_lockSource)
                    {
                        logger.Log(LogLevel.Success, "Remote fetch task completed!");
                        logger.Log(LogLevel.Info, "Parsing remote data...");
                    }
                    return jsonHelper.FromJsonAsync<Region[]>(task.Result);
                }, TaskContinuationOptions.OnlyOnRanToCompletion);
            var filterRemoteRegionsTask = parseRemoteDataTask
                .ContinueWith(task =>
                {
                    lock (s_lockSource)
                    {
                        logger.Log(LogLevel.Success, "Forecasts parsing task completed!");
                        logger.Log(LogLevel.Info, "Merging data...");
                    }

                    Region[] remoteRegions = parseRemoteDataTask.Result.Result;
                    return Task.Run(() => new DataFilter(config).FilterRegions(remoteRegions));
                }, TaskContinuationOptions.OnlyOnRanToCompletion);

            var parseLocalDataTask = localFetchTask
                .ContinueWith(task =>
                {
                    lock (s_lockSource)
                    {
                        logger.Log(LogLevel.Success, "Local fetch task completed!");
                        logger.Log(LogLevel.Info, "Parsing local data...");
                    }
                    return jsonHelper.FromJsonAsync<Region>(task.Result);
                }, TaskContinuationOptions.OnlyOnRanToCompletion);

            var parseTodaysDataTask = todaysFetchTask
                .ContinueWith(task =>
                {
                    lock (s_lockSource)
                    {
                        logger.Log(LogLevel.Success, "Today's fetch task completed!");
                        logger.Log(LogLevel.Info, "Parsing today's data...");
                    }
                    return jsonHelper.FromJsonAsync<Forecast[]>(task.Result);
                }, TaskContinuationOptions.OnlyOnRanToCompletion);


            var mergeTask =
                Task.WhenAll(filterRemoteRegionsTask, parseLocalDataTask)
                .ContinueWith(_ =>
                {
                    lock (s_lockSource)
                    {
                        logger.Log(LogLevel.Success, "Forecasts parsing task completed!");
                        logger.Log(LogLevel.Info, "Merging data...");
                    }

                    Region localInstance = parseLocalDataTask.Result.Result;
                    Region remoteInstance = filterRemoteRegionsTask.Result.Result;

                    var dm = new DataMerger();

                    return Task.Run(() => dm.MergeRegions(localInstance, remoteInstance));
                }, TaskContinuationOptions.OnlyOnRanToCompletion);

            var forecastsSerializationTask = mergeTask
                .ContinueWith(task =>
                {
                    lock (s_lockSource)
                    {
                        logger.Log(LogLevel.Success, "MergeTask completed!");
                        logger.Log(LogLevel.Info, "Serializing forecasts data...");
                    }

                    Region newLocalInstance = task.Result.Result;
                    return jsonHelper.ToJsonAsync(newLocalInstance);
                }, TaskContinuationOptions.OnlyOnRanToCompletion);

            var forecastsStoreTask = forecastsSerializationTask
                .ContinueWith(task =>
                {
                    lock (s_lockSource)
                    {
                        logger.Log(LogLevel.Success, "Forecasts serialization task completed!");
                        logger.Log(LogLevel.Info, "Storing forecasts data...");
                    }

                    var newLocalJson = task.Result.Result;

                    return fileService.PersistAsync(newLocalJson, InOutOptions.ForecastPath);
                }, TaskContinuationOptions.OnlyOnRanToCompletion);


            var todaysDataBuildTask =
                Task.WhenAll(parseTodaysDataTask, filterRemoteRegionsTask)
                .ContinueWith(_ =>
                {
                    lock (s_lockSource)
                    {
                        logger.Log(LogLevel.Success, "Today's weather parsing task completed!");
                        logger.Log(LogLevel.Info, "Building today's data...");
                    }

                    Region remoteInstance = filterRemoteRegionsTask.Result.Result;
                    Forecast[] todaysWeathers = parseTodaysDataTask.Result.Result;

                    var tdb = new TodaysDataBuilder(remoteInstance, todaysWeathers);
                    return Task.Run(() => tdb.Build());
                }, TaskContinuationOptions.OnlyOnRanToCompletion);
            var todaysDataSerializationTask = todaysDataBuildTask
                .ContinueWith(task =>
                {
                    lock (s_lockSource)
                    {
                        logger.Log(LogLevel.Success, "Today's weather data build task completed!");
                        logger.Log(LogLevel.Info, "Serializing today's data...");
                    }

                    return jsonHelper.ToJsonAsync(task.Result.Result);
                }, TaskContinuationOptions.OnlyOnRanToCompletion);
            var todaysDataStoreTask = todaysDataSerializationTask
                .ContinueWith(task =>
                {
                    lock (s_lockSource)
                    {
                        logger.Log(LogLevel.Success, "Today's weather data serialization task completed!");
                        logger.Log(LogLevel.Info, "Storing today's data...");
                    }

                    return fileService.PersistAsync(task.Result.Result, InOutOptions.TodaysPath);
                }, TaskContinuationOptions.OnlyOnRanToCompletion);

            var uiDataBuildTask = Task.WhenAll(mergeTask, todaysDataBuildTask)
                .ContinueWith(_ =>
                {
                    lock (s_lockSource)
                    {
                        logger.Log(LogLevel.Success, "Antecedent tasks completed!");
                        logger.Log(LogLevel.Info, "Building UI data source...");
                    }

                    var newLocalInstance = mergeTask.Result.Result;
                    var newTodaysDatas = todaysDataBuildTask.Result.Result;

                    var usb = new UiSourceBuilder(newLocalInstance, newTodaysDatas);
                    return Task.Run(() => usb.Build());
                }, TaskContinuationOptions.OnlyOnRanToCompletion);


            var uiDataStoreTask = uiDataBuildTask
                .ContinueWith(task =>
                {
                    lock (s_lockSource)
                    {
                        logger.Log(LogLevel.Success, "Building UI data completed!");
                        logger.Log(LogLevel.Info, "Saving UI data to source file...");
                    }

                    return fileService.PersistAsync(task.Result.Result, InOutOptions.ResultPath);
                }, TaskContinuationOptions.OnlyOnRanToCompletion);


            try
            {
                Task.WaitAll(new Task[]
                    {
                localFetchTask,
                remoteFetchTask,
                todaysFetchTask,
                parseLocalDataTask,
                parseRemoteDataTask,
                parseTodaysDataTask,
                mergeTask,
                forecastsStoreTask,
                todaysDataStoreTask,
                uiDataStoreTask
                    });

                sw.Stop();
                var overall = sw.Elapsed.TotalSeconds;
                logger.Log(LogLevel.Success, "All task completed!");
                logger.Log(LogLevel.Info, $"Finished in {overall} second{(overall != 1 ? "s" : "")}");
                if (overall <= 1)
                    logger.Log(LogLevel.Warn, "This application is too fast :)");
            }
            catch (AggregateException ae)
            {
                foreach (var e in ae.Flatten().InnerExceptions)
                    logger.Log(LogLevel.Error,
                        $"Exception has been thrown at: {e.StackTrace}" +
                        $"{Environment.NewLine}\t\t{e.Message}");
            }
            catch (Exception ex)
            {
                logger.Log(LogLevel.Fatal, ex.ToString());
            }

            Console.WriteLine("\nPress any key to continue...");
            Console.ReadKey();
            logger.Dispose();
        }
    }

完整的来源,如果需要进一步的信息。也许还值得一提的是,我使用的是.NET5.0。

共有1个答案

西门马鲁
2023-03-14

它真的会使代码的任何部分同步运行,仅仅是因为缺少一个'await'操作符吗?

是的。main方法将同步运行。这并不重要,因为它是main方法,但如果您想异步等待任务完成,请使用Await Task.WhenAll而不是Task.WaitAll。异步方法还有一个额外的好处,它不将异常包装在aggregateexception中。

请注意,使用await而不是continuewith

 类似资料: