2014-11-03 20 views
5

Cách tốt hơn để tạo trình bao bọc không đồng bộ cho phương thức đồng bộ?Cách tạo trình bao bọc không đồng bộ

// sync method 
public void LongOperation() 
{ 
    //code... 
} 


// versions of wrapper 
public async Task LongOpertionWrapperAsyncV1() 
{ 
    var task = Task.Factory.StartNew(LongOperation); 
    await task.ConfigureAwait(false); 
} 

public Task LongOpertionWrapperAsyncV2() 
{ 
    var task = Task.Factory.StartNew(LongOperation); 
    task.ConfigureAwait(false); 
    return task; 
} 

Mặc dù việc sử dụng cả hai phiên bản đều không khác nhau.

async Task Executor() 
{ 
    await LongOpertionWrapperAsyncV1(); 
    await LongOpertionWrapperAsyncV2(); 
} 

Đối với phương pháp mà trở về giá trị (công tác <T>), tôi sử dụng phiên bản đầu tiên.

Nhưng tôi muốn biết ý kiến ​​của bạn.

Và có sự khác biệt chung giữa các phiên bản này?

+2

Để lưu nội dung: http://blogs.msdn.com/b/pfxteam/archive/2012/03/24/10287244.aspx – ken2k

+0

BTW, điều này: 'task.ConfigureAwait (false);' không làm * bất cứ điều gì *. 'ConfigureAwait()' * trả về * một awaiter, nếu bạn bỏ qua giá trị trả về, nó sẽ không có bất kỳ hiệu ứng nào. – svick

Trả lời

4

Bạn nên sử dụng "một cái gì đó như" V2:

public Task LongOpertionWrapperAsyncV2() 
{ 
    return Task.Run(LongOperation); 
} 

async Task Executor() 
{ 
    await LongOpertionWrapperAsyncV2().ConfigureAwait(false); 
} 

này giúp bạn tiết kiệm một bối cảnh chuyển đổi so với V1. Miễn là bạn không cần phải "chờ đợi một hoạt động khác" và async-Task là hoạt động cuối cùng trong phương thức bạn chỉ có thể trả lại tác vụ thay vì chờ nó và để chờ người gọi (cũng có thể hoặc không thể thêm ConfigureAwait).

Task.Factory.StartNew chỉ cần thiết nếu bạn muốn cung cấp TaskCreationOptions.LongRunning như HPT được đề xuất.

UPDATE:
Như Stephen đã meantioned: Có rất ít trường hợp bạn nên làm async over sync (nhưng có). Vì vậy, suy nghĩ về những gì bạn đang làm trước khi thực hiện một cái gì đó như thế này. Đơn giản nói: Nếu nó là CPU-bound làm việc KHÔNG làm điều đó, nếu nó là một số loại "chờ đợi cho IO" MAYBE làm điều đó.
Chúng tôi có một trường hợp ở đây, nơi chúng tôi đã phát triển thư viện "gần như không đồng bộ", để kiểm soát các thiết bị HW khác nhau. Có cả "generic thư viện" là không đồng bộ, nhưng một số các trình điều khiển thiết bị cấp thấp và/hoặc thư viện truy cập không hỗ trợ async vân vân mức rất thấp nhất chúng tôi làm điều gì đó như:

public async Task<byte[]> ReadAsync(int length) 
{ 
    return Task.Run(() => hwDevice.Read(length)); 
} 

Các hwDevice.Read không vẫn khóa các chủ đề, nhưng không phải là CPU, do đó, giao diện người dùng được đáp ứng trong thời gian đó chúng tôi đang chờ đợi cho IO (trong "thực sự sống" cũng là một số hủy bỏ và xử lý lỗi logic xung quanh nó).

14

Neither solution is correct. Câu trả lời hay nhất là để không hiển thị các phương thức không đồng bộ cho mã đồng bộ. Tôi đi sâu vào "lý do" on my blog.

Nếu mã của bạn không đồng bộ, sau đó sử dụng asyncawait. Nếu không, thì đừng. Nó sẽ được người gọi đến như thế nào họ muốn gọi mã (ví dụ, sử dụng Task.Run).

+0

Có phương tiện chính xác để bao gói một phương thức đồng bộ nên không đồng bộ như không đồng bộ không? I E.Giả sử bạn có phương thức đồng bộ, GetDatabaseData(); kể từ khi các cuộc gọi DB là I/O bị ràng buộc, có một phương tiện để làm cho điều này không đồng bộ? – Mackers

+1

@Mackers: Không. Nếu phương thức không đồng bộ, không có cách nào để "tạo" nó không đồng bộ (trừ khi bạn sửa đổi việc triển khai, tất nhiên). –

+0

@StephenCleary Tôi đã đọc bài đăng "Không chặn trên Async" của bạn. Điều gì xảy ra nếu tôi muốn tạo một trình bao bọc đồng bộ của phương thức async? Tôi có nên sử dụng 'ConfigureAwait' bên trong các phương thức đồng bộ của mình (các trình bao bọc của async) không? – lll

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