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

尝试理解任务。运行异步等待()/Result

斜瑞
2023-03-14

我试图了解 Task.Run Wait() 异步等待是如何工作的。
我已经阅读了这个页面:了解在一行中使用Task.Run Wait()异步等待的使用,但不太理解它。

在我的代码中,我从Microsoft EventHub接收事件,并使用实现IEventProcessor的类处理它们。我在 ConvertToEntity() 中调用 DoOtherWork() 方法,这是一个异步方法,这是一个同步方法。由于该方法是异步的,因此我使用 Task.Run()异步来委派。(即 Task.Run(async () =

我的问题是:
*两者之间有什么区别
*哪种代码是合适的和/或安全的(=不会导致死锁)
*在什么情况下会导致僵局
*为什么任务。Run()解决我遇到的死锁?(详见下文)

注:我在用。网芯3.1。

我为什么使用任务。Run()
当我们使用< code>AbcAsync()时,我的团队出现了几次死锁问题。结果
或< code >。Wait()(该方法是在NET Core Web API方法中调用的,死锁大多发生在我们运行执行该方法的单元测试时),所以我们使用了< code>Task。Run(async () =

public class EventProcessor : IEventProcessor
{
    public async Task ProcessEventsAsync(PartitionContext context, IEnumerable<EventData> messages) 
    {
        ...
        var result = await eventHandler.ProcessAsync(messages);
        ...
    }
}

public Task async ProcessAsync(IEnumerable<EventData> messages)
{
    ...
    var entities = ConvertToEntity(messages);
    ...
}

public List<Entity> ConvertToEntity(IEnumerable<EventData> messages)
{
    var serializedMessages = Serialize(messages);
    var entities = autoMapper.Map<Entity[]>(serializedMessages);

    // Task.Run(async () => entities = await DoAnotherWork(entities)).Wait(); // before change
    entities = DoAnotherWork(entities).Result; // after change

    return entities;
}    

public Task async Entity[] DoAnotherWork(Entity[] entities)
{
    // Do stuff async
    await DoMoreStuff(entities)...
}

共有1个答案

戚阳曜
2023-03-14

两者之间有什么区别?

Task.Run 开始在线程池线程上运行委托;直接调用该方法将开始在当前线程上运行委托。

学习async时,将所有内容都分开,这样您就可以准确地看到发生了什么:

entities = DoAnotherWork(entities).Result;

相当于:

var entitiesTask = DoAnotherWork(entities);
entities = entitiesTask.Result;

和这个代码:

Task.Run(async () => entities = await DoAnotherWork(entities)).Wait();

相当于:

async Task LambdaAsMethod()
{
  entities = await DoAnotherWork(entities);
}
var runTask = Task.Run(LambdaAsMethod);
runTask.Wait();

哪种代码是合适的和/或安全的(=不会导致死锁)?

应避免在 ASP.NET 环境中使用 Task.Run,因为它会干扰线程池的 ASP.NET 处理,并在不需要线程池时强制线程切换。

如果是,在什么情况下会导致死锁?

常见的死锁场景需要两件事:

  1. 阻止异步代码的代码,而不是正确使用awaid
  2. 强制同步的上下文(即,一次只允许上下文中的一个代码块)

最好的解决方案是删除第一个条件;换句话说,一路使用“async”。要在这里应用它,最好的解决方案是完全删除阻塞:

public Task async ProcessAsync(IEnumerable<EventData> messages)
{
    ...
    var entities = await ConvertToEntityAsync(messages);
    ...
}

public async Task<List<Entity>> ConvertToEntityAsync(IEnumerable<EventData> messages)
{
    var serializedMessages = Serialize(messages);
    var entities = autoMapper.Map<Entity[]>(serializedMessages);

    entities = await DoAnotherWork(entities);

    return entities;
}

为什么任务。Run()解决我遇到的死锁?(详见下文)

.NET Core 根本没有“上下文”,因此它使用线程池上下文。由于 .NET Core 没有上下文,因此它会删除死锁的第二个条件,并且不会发生死锁。如果您在 ASP.NET Core 项目中运行它。

我的团队在使用AbcAsync()时多次出现死锁问题。Result或.Wait()(该方法是在NET Core Web API方法中调用的,死锁主要发生在我们运行执行该方法的单元测试时)

一些单元测试框架确实提供了上下文——最明显的是xUnit。xUnit提供的上下文是同步上下文,因此它的行为更像UI上下文或ASP.NET前核心上下文。因此,当您的代码在单元测试中运行时,它确实具有死锁的第二个条件,死锁可能会发生。

如上所述,最佳解决方案是完全去除堵塞;这将有助于提高服务器的效率。但是如果必须完成阻塞,那么您应该将单元测试代码包装在<code>Task中。运行,而不是ASP。NET核心代码。

 类似资料:
  • 我只想确保我很好地理解异步await和task.run或task.whenall之间的区别 所以异步等待就是处理异步方法。它意味着隐含着一个处理顺序。 我在不阻塞主线程的情况下运行了一个很长的处理,并等待结果继续。 对于task.run和task.when,这里有一个多线程的新概念。这意味着我可以在一个新线程上启动一个长进程,它不会等待完成来继续代码。代码在新线程上。在这个线程上,我可以等待方法。

  • 我在网上搜索了很多关于vs await async,但是在这个特定的使用场景中,我并不真正理解其中的区别。我相信情况很简单。 vs. 其中,是一个异步方法,其中包含一些异步调用,例如使用wait调用db。 问题: 在这种情况下,两者之间有什么区别吗?任何帮助或意见,谢谢!

  • 我们有一个async/await方法,它通过实体框架调用存储的过程,该框架由同步方法调用。 需要很长的时间来执行,这可能就是我们编写async/await的原因,它可以被多个地方使用。 我知道我们不应该混合异步和同步调用,但假设我们有这种情况并且我们正在使用 从同步方法 调用异步方法 GetLoanDataAsync,我理解该方法 - 将在后台线程上运行。 我的问题是,如果我们有一个异步方法< c

  • 我一直试图理解C#中的Async/await和Task,但尽管看了youtube视频,阅读了文档,并参加了pluralsight课程,但一直失败得很厉害。 我希望有人能帮助回答这些稍微抽象的问题,帮助我的大脑摆脱困境。 1.为什么说async/await启用了一个“Asynchonrous”方法,而async关键字本身什么也不做,而await关键字添加了一个挂起点?添加挂起点不是强制方法同步操作,

  • 使用asyn/wait vs wait有什么区别task.run() 等待任务。运行示例- 异步等待示例-

  • 问题内容: 我想同时下载一些文件,例如100个文件。因此,我决定将下载线程添加到调度队列中,GCD会调整同时运行多少个线程。 这里的问题是:中的块将立即完成,因为它将在另一个线程上运行。因此,如果长度为100,它将立即创建100个线程。 如何配置块以等待下载任务完成?我不想使用,因为它只允许同时运行一个下载任务。 问题答案: 要扩展Abhinav的答案,您应该: 使用创建一个组。 在开始每个下载任