9

Từ khóa asyncdo làm cho số CIL thay đổi (ngay cả khi không có gì chờ đợi bên trong phương thức), nhưng chủ yếu là để cho phép await hiển thị.Tại sao TCS của tôi không chờ đợi?

Nhưng tôi không mong đợi những điều sau đây xảy ra:

static void Main(string[] args) 
{ 
    Task t = Go(); 
    t.Wait(); 
} 

static async Task Go() 
{ 
    Console.WriteLine(1); 
    await AAA(3000); 
    Console.WriteLine(2); 
} 


static Task<object> AAA(int a) // <--- No `async` 
{ 
    TaskCompletionSource<object> tcs = new TaskCompletionSource<object>(); 
    Task.Delay(a).ContinueWith(b => tcs.SetResult(null)); 
    return tcs.Task; 
} 

in này:

1 
(wait) 
2 

Nhưng nếu tôi thay đổi

static Task<object> AAA(int a) 

để

static async Task<object> AAA(int a) 

It in:

1 
2 
(no wait) 

Câu hỏi

Tại sao tôi không thấy sự chậm trễ? TCS chỉ được giải quyết sau ba giây. Trong khi đó, nhiệm vụ không được giải quyết và nên được chờ đợi.

+2

Tôi nghĩ rằng [razor118] (http://stackoverflow.com/a/32785865/477420) câu trả lời là minh chứng tốt nhất của sự cố - thay đổi 'tác vụ tĩnh AAA (int a)' thành 'tác vụ tĩnh AAA (int a) '(với các thay đổi cần thiết cho mã) và hơn là thêm' async'. –

+0

Vâng, tôi bị cắn bởi như T. nghĩ về nó bây giờ - đó là một câu hỏi ngu ngốc. Mọi kết quả của phương thức async trả về một cái gì đó - rằng một cái gì đó được bao bọc bởi một Task. Vì vậy, ở đây tôi thực sự trở về 'Nhiệm vụ ' –

+1

Ngớ ngẩn hay không phải là cuộc gọi của bạn, nhưng chắc chắn là giáo dục (và được viết tốt). Cả hai phiên bản mã (async/non-async) đều có vẻ hợp lý và làm tôi bối rối (và tôi đặt cược đủ người dựa trên phiếu bầu). –

Trả lời

8

Nếu không có từ khóa async bạn đang trả lại tác vụ của TaskCompletionSource từ AAA và vì vậy bạn đợi cho đến khi hoàn thành (điều này sẽ xảy ra sau khi quá trình trì hoãn hoàn tất).

Tuy nhiên, khi bạn thêm từ khóa async, tác vụ được trả về từ phương pháp là nhiệm vụ của máy nhà nước hoàn thành đồng bộ. Nhiệm vụ đó có bên trong nó (kết quả là) nhiệm vụ của TaskCompletionSource nhưng đó không phải là nhiệm vụ mà bạn đang chờ đợi.

Nếu bạn muốn phương pháp mà phải đợi cho TaskCompletionSource 'Nhiệm vụ của bạn có thể đang chờ đợi các nhiệm vụ bên trong của Task<Task>:

await ((Task) await AAA(3000)); 

Hoặc chờ đợi sự TaskCompletionSource' s thay vì trả lại nó:

async Task AAA(int a) 
{ 
    TaskCompletionSource<object> tcs = new TaskCompletionSource<object>(); 
    Task.Delay(a).ContinueWith(b => tcs.SetResult(null)); 
    await tcs.Task; 
} 

Hoặc thậm chí tốt hơn, chỉ cần chờ Task.Delay chính nó:

async Task<object> AAA(int a) 
{ 
    await Task.Delay(a); 
    return null; 
} 
6

Vì khi bạn trả lại Task từ phương thức không đồng bộ với kiểu trả lại là Task<object>, bạn sẽ nhận được số Task<Task> với công việc của mình (mà bạn mong đợi được chờ đợi) bên trong. Đó là những gì bạn nên làm:

static async Task<object> AAA(int a) 
{ 
    await Task.Delay(a); 
    return null; 
} 

Tóm lại, hãy cố gắng tránh trộn các hoạt động công việc không đồng bộ và chờ đợi trong một phương pháp.

2

Như SERG nói, hãy nhìn vào ví dụ này trong Visual Studio:

 static async Task<int> AAA(int a) // <--- No `async` 
     { 
      TaskCompletionSource<int> tcs = new TaskCompletionSource<int>(); 
      Task.Delay(a).ContinueWith(b => 
      { 
        tcs.SetResult(1); 
      }); 
      return tcs.Task; 
     } 

Bạn sẽ nhận được lỗi như thế này:

Vì đây là một phương pháp không đồng bộ, khái niệm lợi nhuận phải loại 'int' thay vì 'Tác vụ', bởi vì phương pháp của bạn sẽ chạy đồng bộ. Đó là lý do tại sao phải trả lại int, chứ không phải Task.

+2

Đối với lần gửi cuối cùng của bạn, phương thức * sẽ * chạy không đồng bộ và yêu cầu 'int' và không phải là' Task 'được trả về, nhưng thực tế là phương thức chạy đồng bộ là 't * tại sao * anh ta phải trả về 'int'. Anh ta cần trả về một 'int' bởi vì tất cả các phương thức' async' bọc giá trị trả về trong một 'Task'. Rằng phương pháp này sẽ chạy đồng bộ là đúng, nhưng không phải là lý do cho lỗi đó. – Servy

+0

razor118, Câu trả lời đó sẽ rực rỡ như bình luận - sử dụng một số loại mạnh thay vì 'Object' sẽ có lỗi rất rõ ràng. Hoặc bạn có thể xóa sạch bằng cách áp dụng nhận xét của @ Servy. –

+0

Phục vụ như tôi biết từ khóa async chịu trách nhiệm thông báo cho trình biên dịch để xây dựng máy trạng thái. Nó không kết thúc kiểu trả về cho Task . Nhìn vào mã IL đó private static void Test() {} và private static async trống TestAsync() {} – razor118

Các vấn đề liên quan