我是异步/等待C#模型的新手,试图了解这两个选项是否本质上是同一件事:
public Task LongRunningMethod()
{
return Task.Run(async () =>
{
await DoStuff();
});
}
//then call it
await LongRunningMethod();
还有这个
public async Task LongRunningMethod()
{
await DoStuff();
}
//then call it
await LongRunningMethod();
我在想第一种方法将耗尽池中的一个额外线程...并且还将一个Task封装为一个额外Task。还是我错了?
答案 0 :(得分:7)
Task.Run
将其委托放入线程池。这会导致两件事:
DoStuff
之前await
中的任何代码都将在线程池线程上运行,而不是on the calling thread。DoStuff
中的代码将在线程池上下文中运行,而不是using whatever context was current from the calling thread。 大多数,在Task.Run
中进行异步工作是一个错误。但这有时很有用,例如,如果DoStuff
在异步操作之前做了一些繁重的计算工作,那么Task.Run
可用于将工作移出UI线程。
答案 1 :(得分:2)
它们非常相似,但是DoStuff
有可能同步完成;如果发生这种情况,您的第二个方法(仅await
)将阻塞多长时间,而第一个方法(Task.Run
)将始终不完整地返回给调用方(展开其堆栈并安排一个连续),并在池线程上运行阻塞工作。
在不同情况下,两种选择都是理想的!
但是,还有第三种选择,它表达了准确的意图,即“在其他地方运行其余部分” 只要您没有{{1 }}:
SyncContext
如果没有public async Task LongRunningMethod()
{
await Task.Yield();
await DoStuff(); // possibly with .ConfigureAwait(false)
}
,则其功能与SyncContext
版本相似(意味着:它将始终以不完整的形式返回给调用者,并在池上运行Task.Run
),只是:没有实际的DoStuff
位。但是,如果 是Task.Run
:它将回到 same 上下文,这很尴尬,不幸的是没有{{1 }} SyncContext
,因此在这种情况下 您必须使用ConfigureAwait(false)
或类似的语言。
答案 2 :(得分:1)
方法名称传达了这样做的原因,即“ LongRunning”。您可以将创建标志@Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "Reg=%__AppDir__%reg.exe"
Set "Find=%__AppDir__%find.exe"
Set "Key=HKCU\Software\R-core\R"
Set "Val=InstallPath"
Set "RDir="
For /F "EOL=H Tokens=2*" %%G In (
'"%Reg% Query "%Key%" /S /F "%Val%" /V 2>NUL|%Find% "\""') Do Set "RDir=%%~H"
If Not Defined RDir For /F "EOL=H Tokens=2*" %%G In (
'"%Reg% Query "HKLM%Key:~4%" /S /F "%Val%" /V 2>NUL|%Find% "\""'
) Do Set "RDir=%%~H"
If Not Defined RDir GoTo :EOF
If "%PROCESSOR_ARCHITECTURE:~-2%" == "86" (
If Not Defined PROCESSOR_ARCHITEW6432 (Set "RDir=%RDir%\bin\i386"
) Else Set "RDir=%RDir%\bin\x64") Else Set "RDir=%RDir%\bin\x64"
Where /Q "%RDir%":"RScript.exe" && (Set "RDir=%RDir%\RScript.exe") || Set "RDir="
If Defined RDir Echo Your default RScript.exe absolute path is %RDir% & Pause
传递给LongRunning
(此示例没有这样做),并且作为纯实现线程,运行时将为此分配一个单独的线程。
根据情况,即使您的第二个示例也不完全正确。如果这是一个库,那么它实际上应该是Task.Run()
。