我猜我的代码有很多薄弱点,所以请随时分享任何想法。顺便问一下,我的主要问题是,当我尝试执行以下操作时,以及在最后,当我希望等待所有任务(通过使用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。
它真的会使代码的任何部分同步运行,仅仅是因为缺少一个'await'操作符吗?
是的。main
方法将同步运行。这并不重要,因为它是main
方法,但如果您想异步等待任务完成,请使用Await Task.WhenAll
而不是Task.WaitAll
。异步方法还有一个额外的好处,它不将异常包装在aggregateexception
中。
请注意,使用await
而不是continuewith
。
警告试着告诉我什么?我该怎么办? 这是我的代码:它是否使用多线程运行?
在ViewComponent中,我得到了以下警告:(我使用了) 更新: 在视图中,我有:
我有一个接口,其中包含一些返回的函数。实现接口的一些类不需要等待任何东西,而其他类可能只是抛出--因此警告是虚假的和令人讨厌的。
我知道我可以通过等待来修复它,但对于只执行一些廉价操作的方法来说,这感觉不对。这听起来也会给执行增加不必要的开销,但我也不确定这是否已经存在,因为存在关键字。 我应该忽略这些警告,还是有一种我看不到的方法来解决这个问题?
没有await并且在非异步方法中调用异步方法的行为是什么?我这样问是因为我看到Visual Studio在调用异步方法时没有显示任何警告,好像这是一件非常正常的事情。在这种情况下,异步方法的行为是否像是同步的?