以下两段代码之间是否存在任何概念差异:
async Task TestAsync()
{
await Task.Run(() => DoSomeWork());
}
Run Code Online (Sandbox Code Playgroud)
和
Task TestAsync()
{
return Task.Run(() => DoSomeWork());
}
Run Code Online (Sandbox Code Playgroud)
生成的代码也不同吗?
编辑:为避免混淆Task.Run,类似的情况:
async Task TestAsync()
{
await Task.Delay(1000);
}
Run Code Online (Sandbox Code Playgroud)
和
Task TestAsync()
{
return Task.Delay(1000);
}
Run Code Online (Sandbox Code Playgroud)
最新更新:除了接受的答案之外,LocalCallContext处理方式也有所不同:即使没有异步,CallContext.LogicalGetData也会被恢复.为什么?
nos*_*tio 72
更新后,除了下面解释的异常传播行为的差异之外,还有另一个有些微妙的区别:async Task/ Taskversion更容易在非默认同步上下文中死锁.例如,以下内容将在WinForms或WPF应用程序中死锁:
static async Task OneTestAsync(int n)
{
await Task.Delay(n);
}
static Task AnotherTestAsync(int n)
{
return Task.Delay(n);
}
// call DoTestAsync with either OneTestAsync or AnotherTestAsync as whatTest
static void DoTestAsync(Func<int, Task> whatTest, int n)
{
Task task = null;
try
{
// start the task
task = whatTest(n);
// do some other stuff,
// while the task is pending
Console.Write("Press enter to continue");
Console.ReadLine();
task.Wait();
}
catch (Exception ex)
{
Console.Write("Error: " + ex.Message);
}
}
Run Code Online (Sandbox Code Playgroud)
将其更改为非异步版本,它不会死锁:
Press enter to continue Error: One or more errors occurred.await Task.Delay Error: 2nd
Stephen Cleary在他的博客中很好地解释了死锁的本质.
await task方法,获取存储在返回的task.Wait()对象和直到任务被通过观察保持休眠task.Result,task.GetAwaiter().GetResult(),async或OneTestAsync.即使从方法的同步部分抛出,它也会以这种方式传播AnotherTestAsync.
请考虑以下代码,其中DoTestAsync(OneTestAsync, -2)和DoTestAsync(AnotherTestAsync, -2)行为完全不同:
Error: The value needs to be either -1 (signifying an infinite timeout), 0 or a positive integer. Parameter name: millisecondsDelayError: 1st
如果我打电话DoTestAsync,它会产生以下输出:
// async
async Task<int> MethodAsync(int arg)
{
if (arg < 0)
throw new ArgumentException("arg");
// ...
return 42 + arg;
}
// non-async
Task<int> MethodAsync(int arg)
{
var task = new Task<int>(() =>
{
if (arg < 0)
throw new ArgumentException("arg");
// ...
return 42 + arg;
});
task.RunSynchronously(TaskScheduler.Default);
return task;
}
Run Code Online (Sandbox Code Playgroud)
注意,我不得不按下Enter才能看到它.
现在,如果我打电话Task.Delay(-2),里面的代码工作流程Task.Delay(1000)是完全不同的,输出也是如此.这一次,我没有被要求按Enter:
static async Task TestAsync()
{
await Task.Delay(1000);
}
void Form_Load(object sender, EventArgs e)
{
TestAsync().Wait(); // dead-lock here
}
Run Code Online (Sandbox Code Playgroud)
在两种情况下async void,在开始时抛出,同时验证其参数.这可能是一个虚构的场景,但理论上async Task也可能抛出,例如,当底层系统计时器API失败时.
另一方面,错误传播逻辑对于async void方法而言是不同的(与SynchronizationContext.Post方法相反).如果当前线程有一个(.),则会SynchronizationContext.Current != null)立即在当前线程的同步上下文(via ThreadPool.QueueUserWorkItem)中重新抛出一个方法内引发的异常(async否则,它将被重新抛出Task).调用者没有机会在同一堆栈帧上处理此异常.
问:是否有可能模仿RunSynchronously非async基于异步的方法的方法的异常传播行为,以便后者不会抛出相同的堆栈帧?
答:如果真的需要,那么是的,有一个技巧:
Task TestAsync()
{
return Task.Delay(1000);
}
Run Code Online (Sandbox Code Playgroud)
但请注意,在某些条件下(例如,当它在堆栈上太深时),await仍然可以异步执行.
Eri*_*ert 53
有什么区别
Run Code Online (Sandbox Code Playgroud)async Task TestAsync() { await Task.Delay(1000); }和
Run Code Online (Sandbox Code Playgroud)Task TestAsync() { return Task.Delay(1000); }?
我对这个问题很困惑.让我试着用另一个问题回答你的问题来澄清.有什么区别?
Func<int> MakeFunction()
{
Func<int> f = ()=>1;
return ()=>f();
}
Run Code Online (Sandbox Code Playgroud)
和
Func<int> MakeFunction()
{
return ()=>1;
}
Run Code Online (Sandbox Code Playgroud)
?
无论我的两件事之间有什么不同,你的两件事之间的区别也是一样的.
Mar*_*zek 11
第一种方法甚至不编译.
由于'
Program.TestAsync()'是一个返回'Task' 的异步方法,因此返回关键字后面不能跟一个对象表达式.你有意回来'Task<T>'吗?
它一定要是
async Task TestAsync()
{
await Task.Run(() => DoSomeWork());
}
Run Code Online (Sandbox Code Playgroud)这两者之间存在重大的概念差异.第一个是异步的,第二个不是.阅读异步性能:了解异步和等待的成本,以获得更多关于async/的内部结构await.
他们确实生成不同的代码.
.method private hidebysig
instance class [mscorlib]System.Threading.Tasks.Task TestAsync () cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.AsyncStateMachineAttribute::.ctor(class [mscorlib]System.Type) = (
01 00 25 53 4f 54 65 73 74 50 72 6f 6a 65 63 74
2e 50 72 6f 67 72 61 6d 2b 3c 54 65 73 74 41 73
79 6e 63 3e 64 5f 5f 31 00 00
)
.custom instance void [mscorlib]System.Diagnostics.DebuggerStepThroughAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x216c
// Code size 62 (0x3e)
.maxstack 2
.locals init (
[0] valuetype SOTestProject.Program/'<TestAsync>d__1',
[1] class [mscorlib]System.Threading.Tasks.Task,
[2] valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder
)
IL_0000: ldloca.s 0
IL_0002: ldarg.0
IL_0003: stfld class SOTestProject.Program SOTestProject.Program/'<TestAsync>d__1'::'<>4__this'
IL_0008: ldloca.s 0
IL_000a: call valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder::Create()
IL_000f: stfld valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder SOTestProject.Program/'<TestAsync>d__1'::'<>t__builder'
IL_0014: ldloca.s 0
IL_0016: ldc.i4.m1
IL_0017: stfld int32 SOTestProject.Program/'<TestAsync>d__1'::'<>1__state'
IL_001c: ldloca.s 0
IL_001e: ldfld valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder SOTestProject.Program/'<TestAsync>d__1'::'<>t__builder'
IL_0023: stloc.2
IL_0024: ldloca.s 2
IL_0026: ldloca.s 0
IL_0028: call instance void [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder::Start<valuetype SOTestProject.Program/'<TestAsync>d__1'>(!!0&)
IL_002d: ldloca.s 0
IL_002f: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder SOTestProject.Program/'<TestAsync>d__1'::'<>t__builder'
IL_0034: call instance class [mscorlib]System.Threading.Tasks.Task [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder::get_Task()
IL_0039: stloc.1
IL_003a: br.s IL_003c
IL_003c: ldloc.1
IL_003d: ret
} // end of method Program::TestAsync
Run Code Online (Sandbox Code Playgroud)
和
.method private hidebysig
instance class [mscorlib]System.Threading.Tasks.Task TestAsync2 () cil managed
{
// Method begins at RVA 0x21d8
// Code size 23 (0x17)
.maxstack 2
.locals init (
[0] class [mscorlib]System.Threading.Tasks.Task CS$1$0000
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldftn instance class [mscorlib]System.Threading.Tasks.Task SOTestProject.Program::'<TestAsync2>b__4'()
IL_0008: newobj instance void class [mscorlib]System.Func`1<class [mscorlib]System.Threading.Tasks.Task>::.ctor(object, native int)
IL_000d: call class [mscorlib]System.Threading.Tasks.Task [mscorlib]System.Threading.Tasks.Task::Run(class [mscorlib]System.Func`1<class [mscorlib]System.Threading.Tasks.Task>)
IL_0012: stloc.0
IL_0013: br.s IL_0015
IL_0015: ldloc.0
IL_0016: ret
} // end of method Program::TestAsync2
Run Code Online (Sandbox Code Playgroud)| 归档时间: |
|
| 查看次数: |
29129 次 |
| 最近记录: |