2016-11-23 25 views
5

Tôi có phương thức trả về Danh sách <> của một đối tượng. Phương pháp này mất một lúc để chạy.Danh sách <MyObject> không chứa định nghĩa cho GetAwaiter

private List<MyObject> GetBigList() 
{ 
    ... slow stuff 
} 

Phương pháp này được gọi từ 4 hoặc 5 nguồn. Vì vậy, tôi nghĩ rằng tôi sẽ cố gắng và sử dụng async và chờ đợi để giữ cho mọi thứ di chuyển trong khi danh sách này được xây dựng. Tôi thêm phương pháp này:

public async Task<List<MyObject>> GetBigListAsync() 
{ 
    var resultsTask = GetBigList(); 
    var resuls = await resultsTask; 
    return resuls; 
} 

Nhưng, trên dòng này:

var resuls = await resultsTask; 

tôi nhận được lỗi này:

List<MyObject> does not contain a definition for GetAwaiter, and no extension method 'GetAwaiter' accepting a first argument of type List<MyObject> could be found.

tôi thiếu gì?

+1

mã ví dụ của bạn không hiển thị bất kỳ việc sử dụng một công tác trong phương thức GetBigList cũng không được đánh dấu là async, và điều đó có nghĩa là kết quả từ phương thức đó không thể được chờ đợi. –

+0

thử Tác vụ không đồng bộ > GetBigList() – Mate

+2

Hãy nhớ rằng, chờ đợi không thực hiện thao tác đồng bộ thành một thao tác không đồng bộ. Đang chờ đăng ký phần còn lại của phương thức hiện tại như việc tiếp tục hoạt động không đồng bộ * đã tồn tại *. Đang chờ là về * quản lý không đồng bộ *, chứ không phải * tạo nó *. Nếu bạn muốn một hoạt động đồng bộ không đồng bộ, bạn sẽ phải tìm ra cách để thực hiện điều đó. –

Trả lời

9

resultTask chỉ là danh sách được trả lại từ GetBigList(), vì vậy không có gì sẽ xảy ra không đồng bộ ở đó.

Những gì bạn có thể làm là giảm tải công việc to a thread riêng biệt trên threadpool bằng cách sử dụng Task.Run và trả lại awaitable Task đối tượng:

// Bad code 
public Task<List<MyObject>> GetBigListAsync() 
{ 
    return Task.Run(() => GetBigList()); 
} 

Trong khi ở trên ví dụ phù hợp nhất với những gì bạn đang cố gắng để làm, đó là không thực hành tốt nhất. Cố gắng làm cho GetBigList() không đồng bộ hóa một cách tự nhiên hoặc nếu thực sự không có cách nào, hãy để lại quyết định về việc thực thi mã trên một chuỗi riêng biệt với mã gọi điện và không che giấu điều này trong triển khai F.e. nếu mã gọi đã chạy async, không có lý do gì để sinh ra một luồng khác. This article mô tả chi tiết hơn.

5

Có vẻ như bạn là một người mới đến kỳ thú đang chờ đợi. Điều gì thực sự đã giúp tôi hiểu những gì async-await hiện là tương tự nhà hàng được đưa ra bởi Eric Lippert trong this interview. Tìm kiếm ở đâu đó ở giữa cho async đang chờ đợi.

Ở đây, ông mô tả rằng nếu một đầu bếp phải chờ đợi một cái gì đó, thay vì không làm gì, ông bắt đầu nhìn xung quanh để xem liệu ông có thể làm điều gì khác trong thời gian đó không.

Đồng hành chờ đợi không đồng bộ là tương tự. Thay vì chờ một tập tin được đọc, một truy vấn cơ sở dữ liệu để trả về, một trang web sẽ được tải xuống, chuỗi của bạn sẽ đi lên callstack để xem liệu có bất kỳ người gọi nào đang chờ và thực hiện các câu lệnh đó cho đến khi anh ta chờ đợi. Một khi anh ta thấy chờ đợi các chủ đề đi lên ngăn xếp cuộc gọi một lần nữa để xem nếu một trong những người gọi không chờ đợi vv Sau một thời gian khi tập tin được đọc, hoặc truy vấn được hoàn thành vv, các báo cáo sau khi chờ đợi được thực hiện.

Thông thường khi đọc danh sách lớn, chuỗi của bạn sẽ rất bận thay vì chờ đợi một cách nhàn rỗi. Nó không chắc chắn rằng đặt hàng một thread để làm những thứ sẽ cải thiện thời gian cần thiết để đọc danh sách của bạn. Cân nhắc đo cả hai phương pháp.

One reason to use async-await, even if it would lengthen the time needed to read the big list, would be to keep the caller (user interface?) responsive.

Để thực hiện chức năng async của bạn, bạn nên làm như sau:

  • Khai báo chức năng async
  • Thay vì TResult trở Tast<TResult> và thay vì void trở Task
  • Nếu cuộc gọi chức năng của bạn các hàm async khác, hãy xem xét ghi nhớ tác vụ trả về thay vì await, thực hiện các công cụ hữu ích khác mà bạn cần làm và await nhiệm vụ khi bạn cần kết quả.
  • Nếu bạn thực sự muốn để một luồng khác làm những thứ bận rộn. gọi

    Task.Run (() => GetBigList())

và chờ đợi khi bạn cần kết quả.

private async Task<List<MyObject>> GetBigListAsync() 
{ 
    var myTask = Task.Run(() => GetBigList()); 
    // your thread is free to do other useful stuff right nw 
    DoOtherUsefulStuff(); 
    // after a while you need the result, await for myTask: 
    List<MyObject> result = await myTask; 

    // you can now use the results of loading: 
    ProcessResult(result); 
    return result; 
} 

Một lần nữa: nếu bạn không có gì hữu ích để làm trong khi các chủ đề khác đang tải danh sách (như giữ UI đáp ứng), không làm điều này, hoặc ít nhất là biện pháp nếu bạn được nhanh hơn.

bài viết khác đã giúp tôi hiểu async-chờ đã - Async await, bởi bao giờ nên hữu ích Stephen Cleary, - và một chút cao cấp hơn: Async-Wait best practices

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