在同一HTTP请求ASP.NET Core C#中混合异步和同步



在同一个asp.net核心api调用中混合异步和同步调用是不是不好的做法

例如,在以下代码中

方法CropBlackBroderOfAnImageAsync是一种异步方法

另一方面SaveImageForProcessing(文件,sourceFolderPath(;是同步方法

原因:我正在同步调用SaveImageForProcessing,我想使用它的结果来执行CropBlackBroderOfAnImageAsync 中的代码

完整的代码回购

欢迎进行代码审查:https://github.com/aamir-poswal/ImageCropApp/

public async Task<(string sourceFolderPath, string destinationFolderPath)> CropBlackBorderOfAnImage(IFormFile file)
{
var extension = Path.GetExtension(file.FileName);
var newFileName = Guid.NewGuid().ToString();//Create a new Name for the file due to security reasons.
var fileNameSource = newFileName + extension;
var sourceFolderPath = Path.Combine(Directory.GetCurrentDirectory(), "Images\Source", fileNameSource);
var fileNameDestination = newFileName + "Result" + extension;
var destinationFolderPath = Path.Combine(Directory.GetCurrentDirectory(), "Images\Destination", fileNameDestination);
SaveImageForProcessing(file, sourceFolderPath);
await _imageCropBlackBroderService.CropBlackBroderOfAnImageAsync(sourceFolderPath, destinationFolderPath);
return (sourceFolderPath, destinationFolderPath);
}
private void SaveImageForProcessing(IFormFile file, string path)
{
using (var bits = new FileStream(path, FileMode.Create))
{
file.CopyTo(bits);
}
}

是的,这是一种糟糕的做法。如果在异步代码中使用长同步操作,那么也将冻结所有其他异步代码。原因是异步代码通常在一个线程中运行。如果该线程正忙于等待一个长操作,那么它就无法处理其他异步代码。

相反,只需使用CopyToAsync,并将SaveImageForProcessing转换为异步函数。

原因:我正在同步调用SaveImageForProcessing,我希望使用它的结果来执行CropBlackBroderOfAnImageAsync 中的代码

我认为您误解了异步的含义。当代码异步运行时,这意味着当前线程在等待时可以自由地做其他事情。阅读文章异步编程和等待可能会有所帮助。它有一个关于做早餐的非常有用的插图。

听起来您认为异步运行意味着代码将在其他代码运行的同时在其他地方运行。这就是所谓的"平行"。

asyncawait的目的是使启动异步任务变得容易,并在准备好结果时返回到它们。在您的情况下,由于您想要立即得到结果,您可以使SaveImageForProcessing异步,使用CopyToAsyncawait。然后您可以立即使用结果。

因为您使用await,所以当您到达呼叫CropBlackBroderOfAnImageAsync的线路时,可以保证SaveImageForProcessing已经完全完成。

public async Task<(string sourceFolderPath, string destinationFolderPath)> CropBlackBorderOfAnImage(IFormFile file)
{
var extension = Path.GetExtension(file.FileName);
var newFileName = Guid.NewGuid().ToString();//Create a new Name for the file due to security reasons.
var fileNameSource = newFileName + extension;
var sourceFolderPath = Path.Combine(Directory.GetCurrentDirectory(), "Images\Source", fileNameSource);
var fileNameDestination = newFileName + "Result" + extension;
var destinationFolderPath = Path.Combine(Directory.GetCurrentDirectory(), "Images\Destination", fileNameDestination);
await SaveImageForProcessing(file, sourceFolderPath);
await _imageCropBlackBroderService.CropBlackBroderOfAnImageAsync(sourceFolderPath, destinationFolderPath);
return (sourceFolderPath, destinationFolderPath);
}
private async Task SaveImageForProcessing(IFormFile file, string path)
{
using (var bits = new FileStream(path, FileMode.Create))
{
await file.CopyToAsync(bits);
}
}

这一切都取决于您的应用程序。在异步函数内部调用同步函数是完全可以的。不过,你可能会留下一些表演。不过,如果您已经在以异步方式进行操作,那么在异步函数中,您还可以使用异步文件IO方法。async函数中的代码仍然可以是异步的,并且仍然以正确的顺序执行(这似乎是您关心的问题(,您只需要await结果,并在后面的代码行中使用它们。

更大的问题是试图屏蔽async调用,使其看起来像sync,反之亦然。

你可以看看这些帖子:

异步上的同步

异步过同步

最新更新