简体   繁体   English

正在进行长时间运行的调用异步这么简单吗?

[英]Is making long-running calls async this simple?

I've just, for a rough draft, converted a whole lot of data access methods to async using the following pattern, and it looks too simple to be good enough for later iterations. 我只是,为了粗略的草案,使用以下模式将大量数据访问方法转换为异步,并且它看起来太简单,不适合以后的迭代。 How safe is it, what is missing, and how should I be doing it? 它有多安全,缺少什么,我应该怎么做?

The service that provides long-running calls: 提供长时间呼叫的服务:

private class UserService
{
    public IdentityUser GetById(int id)
    {
        ...
    }
}

private UserService _userService = new UserService();

The original synchronous method: 原始的同步方法:

public IdentityUser GetById(int id)
{
    return _userService.GetById(id);
}

My fantastic new async method: 我奇妙的新异步方法:

public async Task<IdentityUser> GetByIdAsync(int id)
{
    await Task.Run(() => _userService.GetById(id));
}

You should not make "fake async" methods like this: 你不应该像这样做“假异步”方法:

public async Task<IdentityUser> GetByIdAsync(int id)
{
    await Task.Run(() => _userService.GetById(id));
}

The reason I call it "fake async" is because there is nothing intrinsically async about the operation. 我称之为“假异步”的原因是因为没有任何关于操作的内在异步。 In this case, you should have only the synchronous method. 在这种情况下,您应该只有同步方法。 If a caller wants to make it async by using Task.Run , he can do that. 如果调用者想通过使用Task.Run使其异步,他可以这样做。

When is something intrinsically async? 什么时候本质上是异步的? When you make a request to a web service or a database, for example, between sending the request and receiving the response there is a waiting period - the request is an intrinsically async operation. 当您向Web服务或数据库发出请求时,例如,在发送请求和接收响应之间存在等待时间 - 请求是本质上异步操作。 To avoid blocking the calling thread, use async-await. 要避免阻塞调用线程,请使用async-await。

Technically, that works, but it works by creating a new thread to perform a synchronous operation, which itself is wrapping and blocking on an inherently asynchronous operation. 从技术上讲,这是有效的,但它的工作原理是创建一个新线程来执行同步操作,该操作本身就是在一个固有的异步操作中进行包装和阻塞。 That means you're not getting some of the biggest benefits of going async in the first place. 这意味着你没有从一开始就获得async一些最大好处。

The right way is to go asynchronous all the way. 正确的方法是一路异步。 Whereas right now you probably have something like this: 现在你可能有类似这样的东西:

private class UserService
{
    public IdentityUser GetById(int id)
    {
        return mContext.Users.Single(u => u.Id == id);
    }
}

... you should now create an async version: ...你现在应该创建一个异步版本:

private class UserService
{
    public async Task<IdentityUser> GetByIdAsync(int id)
    {
        return await mContext.Users.SingleAsync(u => u.Id == id);
    }
}

Usage: 用法:

public async Task<IdentityUser> GetByIdAsync(int id)
{
    return await _userService.GetByIdAsync(id);
}

Supposing, of course, that your underlying framework supports asynchronous methods like SingleAsync() for inherently asynchronous operations, this will allow the system to release the current thread while you wait for the database operation to complete. 当然,假设您的底层框架支持异步方法(如SingleAsync()用于固有的异步操作),这将允许系统在您等待数据库操作完成时释放当前线程。 The thread can be reused elsewhere, and when the operation is done, you can use whatever thread happens to be available at that time. 该线程可以在其他地方重用,当操作完成后,您可以使用当时可用的任何线程。

It's probably also worth reading about and adopting these Best Practices . 它可能也值得阅读并采用这些最佳实践 You'll probably want to use .ConfigureAwait(false) anywhere that you're not accessing contextual information like sessions and requests, for example. 例如,您可能希望在不访问会话和请求等上下文信息的任何地方使用.ConfigureAwait(false)

This answer assumes, of course, that GetById is inherently asynchronous: you're retrieving it from a hard drive or network location or something. 当然,这个答案假定GetById本质上是异步的:您从硬盘驱动器或网络位置或其他东西检索它。 If it's calculating the user's ID using a long-running CPU operation, then Task.Run() is a good way to go, and you'll probably want to additionally specify that it's a long-running task in the arguments to Task.Run() . 如果它使用长时间运行的CPU操作来计算用户的ID,那么Task.Run()是一个很好的方法,你可能还想在Task.Run()的参数中另外指定它是一个长时间运行的任务。 Task.Run()

Task.Run () should only be used for CPU-bound work. Task.Run()只应用于受CPU限制的工作。 Don't quite remember why though. 不记得为什么。 Try to make a GetByIdAsync () method instead, that ultimately calls an async resource. 尝试改为使用GetByIdAsync()方法,最终调用异步资源。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Azure长期运行的外部Web服务调用 - Azure Long-running external web service calls 通过Web服务异步执行长时间运行的存储过程 - Async execution of a long-running stored procedure via a webservice MVVM-无需异步等待即可长时间运行的操作 - MVVM - long-running operation without async-await 使用同步长时间运行的任务创建异步方法 - Create async method using sync long-running tasks 使用 async/await 并行处理多个长时间运行的任务 - Parallelizing multiple long-running tasks with async/await 异步/等待具有进度/取消的长时间运行的API方法 - Async/await for long-running API methods with progress/cancelation Task.Run与直接异步调用,用于启动长时间运行的异步方法 - Task.Run vs. direct async call for starting long-running async methods 在后台运行一个长时间运行的并行任务,同时允许小的异步任务更新前台 - Running a long-running parallel task in the background, while allowing small async tasks to update the foreground ASP.NET Web API - 多个长时间运行的 ZDB974238714CA8DE634A7CE1D083A1 调用最佳实践? - ASP.NET Web API - Multiple Long-Running API calls best practices? 如何在C#Winforms应用程序中取消长时间运行的异步任务的执行 - How to cancel execution of a long-running async task in a C# Winforms app
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM