我听过很多关于Async
和await
的内容,并对此有基本的了解,但我的知识有限。
它目前分散在我正在处理的所有项目中,我试图了解使用async
awaited
方法的含义
例如:
public async Task<int> getNumber()
{
return await getFirstNumber();
}
public async Task<int> getFirstNumber()
{
return 1;
}
请注意,在上面的示例中,两种方法都是async
- 但只有getNumber调用等待。
这是一个问题,如果是,那么问题是什么?
如果getFirstNumber()
进行数据库调用或其他I / O,或者其他可能很慢的事情,该怎么办?
这是我应该不惜一切代价避免的,或者有时候是否可以,如果是这样,在什么情况下?
编辑: 异步/等待警告未激活我的VS版本,所以我的代码运行正常。
答案 0 :(得分:3)
这只是一个问题,因为async
/ await
模式有一些与之相关的开销,在这种情况下并不常用。相反,您可以直接返回任务。
public Task<int> getFirstNumber()
{
return Task.FromResult(1);
}
请记住,使用async/await
只是实施细节并且不会影响&#34;界面&#34;或方法的面向公众的合同。因此,如果有一天您需要getFirstNumber()
进行数据库调用,则可以在不违反方法签名设置的期望的情况下切换回使用async
/ await
。
如果您有兴趣,可以使用async / await模式获取getFirstNumber的IL代码:
getFirstNumber:
IL_0000: newobj UserQuery+<getFirstNumber>d__1..ctor
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldarg.0
IL_0008: stfld UserQuery+<getFirstNumber>d__1.<>4__this
IL_000D: ldloc.0
IL_000E: call System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Int32>.Create
IL_0013: stfld UserQuery+<getFirstNumber>d__1.<>t__builder
IL_0018: ldloc.0
IL_0019: ldc.i4.m1
IL_001A: stfld UserQuery+<getFirstNumber>d__1.<>1__state
IL_001F: ldloc.0
IL_0020: ldfld UserQuery+<getFirstNumber>d__1.<>t__builder
IL_0025: stloc.1
IL_0026: ldloca.s 01
IL_0028: ldloca.s 00
IL_002A: call System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Int32>.Start<<getFirstNumber>d__1>
IL_002F: ldloc.0
IL_0030: ldflda UserQuery+<getFirstNumber>d__1.<>t__builder
IL_0035: call System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Int32>.get_Task
IL_003A: ret
<getFirstNumber>d__1.MoveNext:
IL_0000: ldarg.0
IL_0001: ldfld UserQuery+<getFirstNumber>d__1.<>1__state
IL_0006: stloc.0
IL_0007: nop
IL_0008: ldc.i4.1
IL_0009: stloc.1
IL_000A: leave.s IL_0024
IL_000C: stloc.2
IL_000D: ldarg.0
IL_000E: ldc.i4.s FE
IL_0010: stfld UserQuery+<getFirstNumber>d__1.<>1__state
IL_0015: ldarg.0
IL_0016: ldflda UserQuery+<getFirstNumber>d__1.<>t__builder
IL_001B: ldloc.2
IL_001C: call System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Int32>.SetException
IL_0021: nop
IL_0022: leave.s IL_0039
IL_0024: ldarg.0
IL_0025: ldc.i4.s FE
IL_0027: stfld UserQuery+<getFirstNumber>d__1.<>1__state
IL_002C: ldarg.0
IL_002D: ldflda UserQuery+<getFirstNumber>d__1.<>t__builder
IL_0032: ldloc.1
IL_0033: call System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Int32>.SetResult
IL_0038: nop
IL_0039: ret
<getFirstNumber>d__1.SetStateMachine:
IL_0000: ret
<getFirstNumber>d__1..ctor:
IL_0000: ldarg.0
IL_0001: call System.Object..ctor
IL_0006: nop
IL_0007: ret
以下是使用Task.FromResult():
的样子getFirstNumber:
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: call System.Threading.Tasks.Task.FromResult<Int32>
IL_0007: stloc.0
IL_0008: br.s IL_000A
IL_000A: ldloc.0
IL_000B: ret
答案 1 :(得分:1)
有些人说你的getFirstNumber
方法中的任务是没用的,我会更进一步说,在你的方法中,等待任务并没有给你带来任何好处。
等待任务的想法通常与以下事实有关:
您需要该任务的结果(适用于Task<TResult>
),或;
您希望确保任务完全执行,以便您可以继续下一个语句;
我不认为你的例子就是这种情况。你可以简单地写:
public Task<int> getNumber()
{
return getFirstNumber();
}
public Task<int> getFirstNumber()
{
return Task.FromResult(1);
}
在实际场景中,想象一下使用Entity Framework访问数据层的Repository类。使用这样的方法没有错:
public Task<int> GetLatestUserId ()
{
var resultTask = db.Users.Select(u => u.Id).OrderByDesc(id => id).FirstAsync();
return resultTask;
}
此方法的调用者可能必须等待此返回的任务才能使用互联网值(int I'd = await repository.GetLatestUserId()
),因此,它必须是async
方法。