private void RunAsync()
{
string param = "Hi";
Task.Run(() => MethodWithParameter(param));
}
private void MethodWithParameter(string param)
{
}
Biên tập
Do nhu cầu phổ biến, tôi phải lưu ý rằng trình Taskkhởi chạy sẽ chạy song song với luồng gọi. Giả sử mặc định TaskSchedulerđiều này sẽ sử dụng .NET ThreadPool. Dù sao đi nữa, điều này có nghĩa là bạn cần tính đến bất kỳ (các) tham số nào được chuyển đến Taskcó khả năng được nhiều luồng truy cập cùng một lúc, làm cho chúng ở trạng thái chia sẻ. Điều này bao gồm việc truy cập chúng trên chuỗi gọi.
Trong đoạn mã trên của tôi, trường hợp đó được thực hiện hoàn toàn tranh luận. Chuỗi là bất biến. Đó là lý do tại sao tôi sử dụng chúng làm ví dụ. Nhưng nói rằng bạn không sử dụng String...
Một giải pháp là sử dụng asyncvà await. Điều này, theo mặc định, sẽ nắm bắt SynchronizationContextluồng đang gọi và sẽ tạo ra một phần tiếp theo cho phần còn lại của phương thức sau khi gọi tới awaitvà gắn nó vào phần đã tạo Task. Nếu phương thức này đang chạy trên chuỗi WinForms GUI thì nó sẽ thuộc loại WindowsFormsSynchronizationContext.
Phần tiếp theo sẽ chạy sau khi được đăng trở lại phần đã chụp SynchronizationContext- chỉ một lần nữa theo mặc định. Vì vậy, bạn sẽ trở lại chuỗi mà bạn đã bắt đầu sau awaitcuộc gọi. Bạn có thể thay đổi điều này theo nhiều cách khác nhau, đặc biệt là sử dụng ConfigureAwait. Nói tóm lại, phần còn lại của phương pháp đó sẽ không tiếp tục cho đến khi sau khi các Taskđã hoàn thành trên thread khác. Nhưng luồng gọi sẽ tiếp tục chạy song song, không chỉ là phần còn lại của phương thức.
Việc chờ đợi này để hoàn tất việc chạy phần còn lại của phương thức có thể mong muốn hoặc không. Nếu không có gì trong phương thức đó sau này truy cập vào các tham số được truyền đến Taskmà bạn có thể không muốn sử dụng await.
Hoặc có thể bạn sử dụng các tham số đó sau này trong phương thức. Không có lý do gì để awaitngay lập tức vì bạn có thể tiếp tục làm việc một cách an toàn. Hãy nhớ rằng, bạn có thể lưu trữ giá trị Tasktrả về trong một biến và awaittrên đó sau này - ngay cả trong cùng một phương thức. Ví dụ, một khi bạn cần truy cập các tham số đã truyền một cách an toàn sau khi thực hiện một số công việc khác. Một lần nữa, bạn không cần phải awaitở Taskbên phải khi bạn chạy nó.
Tuy nhiên, một cách đơn giản để làm cho chuỗi này an toàn đối với các tham số được truyền đến Task.Runlà thực hiện điều này:
Đầu tiên bạn phải trang trí RunAsyncbằng async:
private async void RunAsync()
Lưu ý quan trọng
Tốt hơn là phương thức được đánh dấu không được trả về giá trị vô hiệu, như tài liệu liên kết đã đề cập. Ngoại lệ phổ biến cho điều này là các trình xử lý sự kiện chẳng hạn như nhấp vào nút và tương tự. Chúng phải trả về giá trị vô hiệu. Nếu không, tôi luôn cố gắng trả về một hoặc khi sử dụng . Đó là một thực hành tốt vì một số lý do.async TaskTask<TResult>async
Bây giờ bạn có thể awaitchạy Tasknhư bên dưới. Bạn không thể sử dụng awaitmà không có async.
await Task.Run(() => MethodWithParameter(param));
Vì vậy, nói chung, nếu bạn thực awaithiện nhiệm vụ, bạn có thể tránh coi các tham số được truyền vào như một tài nguyên được chia sẻ tiềm năng với tất cả các cạm bẫy của việc sửa đổi thứ gì đó từ nhiều luồng cùng một lúc. Ngoài ra, hãy cẩn thận với việc đóng cửa . Tôi sẽ không trình bày sâu về những vấn đề đó nhưng bài viết được liên kết thực hiện rất tốt.
Ghi chú bên lề
Hơi lạc đề một chút, nhưng hãy cẩn thận khi sử dụng bất kỳ loại "chặn" nào trên chuỗi GUI của WinForms do nó được đánh dấu bằng [STAThread]. Sử dụng awaitsẽ không chặn, nhưng đôi khi tôi thấy nó được sử dụng kết hợp với một số loại chặn.
"Block" nằm trong dấu ngoặc kép vì về mặt kỹ thuật, bạn không thể chặn luồng GUI WinForms . Có, nếu bạn sử dụng locktrên chuỗi WinForms GUI, nó sẽ vẫn bơm thông báo, mặc dù bạn nghĩ rằng nó bị "chặn". Nó không thể.
Điều này có thể gây ra các vấn đề kỳ lạ trong một số trường hợp rất hiếm. lockVí dụ, một trong những lý do bạn không bao giờ muốn sử dụng khi vẽ tranh. Nhưng đó là một trường hợp ngoài lề và phức tạp; tuy nhiên tôi đã thấy nó gây ra các vấn đề điên rồ. Vì vậy, tôi ghi nhận nó vì lợi ích hoàn chỉnh.