簡體   English   中英

內部不使用等待的異步方法,因此是同步的

[英]Async method that doesn't use an await internally, so is synchronous

我已經聽說了很多有關Asyncawait ,並且對它有基本的了解,但是我的知識是有限的。

目前,它散布在我正在處理的項目中,我正在嘗試了解未awaited async方法的含義

例如這樣的事情:

public async Task<int> getNumber()
{
     return await getFirstNumber();    
}

public async Task<int> getFirstNumber()
{
     return 1;
}

注意,在上面的示例中,這兩種方法都是async -但只有getNumber調用處於等待狀態。

這是一個問題嗎?如果是,那是什么問題?

如果getFirstNumber()進行了數據庫調用或其他一些I / O或其他可能很慢的操作,該怎么辦?

我應該不惜一切代價避免這種情況,還是有時候可以,如果可以,在什么情況下?

編輯:我的VS版本的異步/等待警告未激活,因此我的代碼在上面運行良好。

這只是一個問題,因為async / await模式具有一些與之相關的開銷,這種開銷在這種情況下沒有用。 相反,您可以直接返回任務。

public Task<int> getFirstNumber()
{
     return Task.FromResult(1);
}

請記住,使用async/await只是實現細節 ,不會影響方法的“接口”或面向公眾的約定。 因此,如果有一天需要getFirstNumber()進行數據庫調用,則可以隨意切換回使用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         

有人說您的getFirstNumber方法中的Task是無用的,我甚至會進一步說,在您的兩種方法中,等待任務都不會給您帶來任何好處。 等待任務的想法通常與以下事實有關:

  • 您需要該任務的結果(對於Task<TResult> ), 或者

  • 您想確保任務完全執行,以便繼續執行下一條語句;

在您的示例中,我認為情況並非如此。 您可以簡單地寫:

public Task<int> getNumber()
{
     return getFirstNumber();    
}

public Task<int> getFirstNumber()
{
     return Task.FromResult(1);
}

在現實世界中,想象一個使用實體框架訪問數據層的存儲庫類。 擁有這樣的方法沒有錯:

public Task<int> GetLatestUserId ()
{
    var resultTask = db.Users.Select(u => u.Id).OrderByDesc(id => id).FirstAsync();
    return resultTask;
}

此方法的調用者可能必須等待此返回的任務才能使用Internet值( int I'd = await repository.GetLatestUserId() ),因此,它必須是async方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM