使用 Task.Run 调用异步方法似乎是错误的?
Calling an async method using a Task.Run seems wrong?
我最近发现了这段代码,它是由我们为我们工作的承包商编写的。它要么非常聪明,要么非常愚蠢(我认为是后者,但我想要第二个意见)。我在 async
await
.
上并没有跟上速度
基本上它是这样工作的:
public bool Send(TemplatedMessageDto message)
{
return Task.Run(() => SendAsync(message))
.GetAwaiter()
.GetResult();
}
public async Task<bool> SendAsync(TemplatedMessageDto message)
{
//code doing stuff
var results = await _externalresource.DothingsExternally();
//code doing stuff
}
据我了解,第一个 Task.Run()
毫无意义且效率低下?应该是:
public bool Send(TemplatedMessageDto message)
{
return SendAsync(message))
.GetAwaiter()
.GetResult();
}
public async Task<bool> SendAsync(TemplatedMessageDto message)
{
//code doing stuff
var results = await _externalresource.DothingsExternally();
//code doing stuff
}
我也不相信这真的是一个异步方法,因为它仍然会等待,对吧?我认为唯一的好处(甚至重写)是释放主工作线程。
有人可以确认第一个任务不应该存在吗?
I'm also not convinced this is really an async method because it will still wait, right?
您的承包商所做的是使用 sync over async anti-pattern。他这样做可能是为了避免创建一个同步完成其工作的附加方法。他不必要地调用 Task.Run
并立即使用 GetResult
阻止它。
使用 GetAwaiter().GetResult()
将传播内部异常,如果发生这种情况,而不是包装 AggregateException
.
I think it's only advantage (even re-written) is to free up the main worker thread.
你的版本和他的版本都会在执行时阻塞主线程,而他的版本也会通过使用线程池线程来执行。正如 Bar 所提到的,这有助于避免与同步上下文编组有关的问题出现死锁。如果需要,我建议创建同步等效项。
I'm also not convinced this is really an async method because it will still wait, right?
正如 Yuval 解释的那样,事实并非如此。你不应该使用同步而不是异步。
Now as I understand it that first Task.Run()
is pointless and inefficient?
不是,以这种方式使用 Task.Run
是有价值的。
由于您正在阻塞异步方法(您不应该这样做),因此您有可能会陷入僵局。这种情况发生在 UI 应用程序和 asp.net 中,您有 SynchronizationContext
.
使用 Task.Run
清除 SynchronizationContext
因为它将工作卸载到 ThreadPool
线程并消除了死锁的风险。
所以,阻塞是不好的,但如果你最终这样做,使用 Task.Run
更安全。
我最近发现了这段代码,它是由我们为我们工作的承包商编写的。它要么非常聪明,要么非常愚蠢(我认为是后者,但我想要第二个意见)。我在 async
await
.
基本上它是这样工作的:
public bool Send(TemplatedMessageDto message)
{
return Task.Run(() => SendAsync(message))
.GetAwaiter()
.GetResult();
}
public async Task<bool> SendAsync(TemplatedMessageDto message)
{
//code doing stuff
var results = await _externalresource.DothingsExternally();
//code doing stuff
}
据我了解,第一个 Task.Run()
毫无意义且效率低下?应该是:
public bool Send(TemplatedMessageDto message)
{
return SendAsync(message))
.GetAwaiter()
.GetResult();
}
public async Task<bool> SendAsync(TemplatedMessageDto message)
{
//code doing stuff
var results = await _externalresource.DothingsExternally();
//code doing stuff
}
我也不相信这真的是一个异步方法,因为它仍然会等待,对吧?我认为唯一的好处(甚至重写)是释放主工作线程。
有人可以确认第一个任务不应该存在吗?
I'm also not convinced this is really an async method because it will still wait, right?
您的承包商所做的是使用 sync over async anti-pattern。他这样做可能是为了避免创建一个同步完成其工作的附加方法。他不必要地调用 Task.Run
并立即使用 GetResult
阻止它。
使用 GetAwaiter().GetResult()
将传播内部异常,如果发生这种情况,而不是包装 AggregateException
.
I think it's only advantage (even re-written) is to free up the main worker thread.
你的版本和他的版本都会在执行时阻塞主线程,而他的版本也会通过使用线程池线程来执行。正如 Bar 所提到的,这有助于避免与同步上下文编组有关的问题出现死锁。如果需要,我建议创建同步等效项。
I'm also not convinced this is really an async method because it will still wait, right?
正如 Yuval 解释的那样,事实并非如此。你不应该使用同步而不是异步。
Now as I understand it that first
Task.Run()
is pointless and inefficient?
不是,以这种方式使用 Task.Run
是有价值的。
由于您正在阻塞异步方法(您不应该这样做),因此您有可能会陷入僵局。这种情况发生在 UI 应用程序和 asp.net 中,您有 SynchronizationContext
.
使用 Task.Run
清除 SynchronizationContext
因为它将工作卸载到 ThreadPool
线程并消除了死锁的风险。
所以,阻塞是不好的,但如果你最终这样做,使用 Task.Run
更安全。