gpt4 book ai didi

c# - 从同步代码调用异步方法并阻塞直到任务完成的正确方法是什么?

转载 作者:太空宇宙 更新时间:2023-11-03 23:38:56 25 4
gpt4 key购买 nike

<分区>

考虑这段代码:

public async Task DoStuffAsync() {
await WhateverAsync(); // Stuff that might take a while
}

// Elsewhere in my project...
public async Task MyMethodAsync() {
await DoStuffAsync();
}

public void MyMethod() {
DoStuffAsync(); // <-- I want this to block until Whatever() is complete.
}

我想提供两种具有相同功能的方法:一种异步运行的异步方法,一种阻塞的非异步方法,这两种方法中的任何一种都可以调用,具体取决于我调用的代码是否是也异步。

我不想到处重复加载代码并为每个方法创建两个版本,这既浪费时间和精力又降低了可维护性。

我猜我可以执行以下操作之一:

// Call it just like any other method... 
// the return type would be Task though which isn't right.
DoStuffAsync();

// Wrap it in a Task.Run(...) call, this seems ok, but
// but is doesn't block, and Task.Run(...) itself returns an
// awaitable Task... back to square one.
Task.Run(() => DoStuffAsync());

// Looks like it might work, but what if I want to return a value?
DoStuffAsync().Wait();

正确的做法是什么?

更新

感谢您的回答。一般建议似乎只是提供异步方法并让消费者决定,而不是创建包装器方法。

但是,让我试着解释一下我在现实世界中遇到的问题......

我有一个 UnitOfWork包装 EF6 的 SaveChanges() 和 SaveChangesAsync() 方法的类 DbContext .我还有一个 List<MailMessage>当 SaveChanges() 成功时需要发送的电子邮件。所以我的代码看起来像这样:

private readonly IDbContext _ctx;
private readonly IEmailService _email;
private readonly List<MailMessage> _emailQueue;

// ....other stuff

public void Save() {
try {
_ctx.SaveChanges();
foreach (var email in _emailQueue) _email.SendAsync(email).Wait();

} catch {
throw;
}
}

public async Task SaveAsync() {
try {
await _ctx.SaveChangesAsync();
foreach (var email in _emailQueue) await _email.SendAsync(email);

} catch {
throw;
}
}

所以你可以看到,因为 EF6 DbContext提供异步和非异步版本,我也有点必须...根据目前的答案,我添加了 .Wait()到我的SendAsync(email)方法,它通过 SMTP 异步发送电子邮件。

所以...一切都很好,除了死锁问题...我该如何避免死锁?

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com