Tạo một nhiệm vụ hoàn thành


197

Tôi muốn tạo một hoàn thành Task(không Task<T>). Có một cái gì đó được xây dựng trong .NET để làm điều này?

Một câu hỏi liên quan: Tạo một tác vụ hoàn thành <T>


2
It seems like the answer I'm getting from everyone is that using a garbage value like this is the correct way. That there isn't a way to do this without the garbage value is disappointing -- oh well.Bạn nghĩ vấn đề này có vấn đề gì? Nếu bạn lưu trữ một bộ đệm Taskthì toàn bộ chương trình của bạn sẽ chiếm thêm một chút bộ nhớ. Không có gì . Ngoài ra, người ta có thể tạo ra một nhiệm vụ hoàn thành mà không làm điều đó, nó sẽ không tốt hơn.
Phục vụ

10
Ôi nỗi thất vọng của tôi không liên quan gì đến việc phải sử dụng thêm bộ nhớ. Chỉ là giá trị rác ở bất cứ đâu trong mã đều không thanh lịch.
Timothy Shields

1
Lưu ý rằng hôm nay có ValueTaskcác nhiệm vụ đã hoàn thành (nghĩa là đối với các giá trị bạn đã có để mã về cơ bản là đồng bộ), điều này sẽ giúp bạn tiết kiệm một khoản phân bổ.
nawfal

Câu trả lời:


247

Các phiên bản mới nhất của Net (v4.6) sẽ bổ sung chỉ vậy, một built-in Task.CompletedTask :

Task completedTask = Task.CompletedTask;

Thuộc tính đó được triển khai dưới dạng một singleton không khóa, do đó bạn hầu như sẽ luôn sử dụng cùng một nhiệm vụ đã hoàn thành.


1
Chỉ cần kiểm tra VS 14 CTP mới nhất và tạo dự án 4.5.3, Task.CompletedTaskvẫn là nội bộ.
Peter Ritchie

1
2. Bạn chưa tải xuống CTP mới nhất (có 4 và được liên kết từ trang web đó) hoặc bạn chưa chỉ định phiên bản 4.5.3. Đây là những gì trên máy của tôi . @PeterRitchie
i3arnon

Tôi đã tạo một VM từ hình ảnh Visual Studio 14 trên Azure.
Peter Ritchie


Tôi đang làm việc trên Mac OS X với mono 5.4.1.7 và tôi gặp lỗi tương tự. Làm thế nào tôi có thể sửa lỗi này?
Khaled Annajar

153

Task<T>hoàn toàn có thể chuyển đổi thành Task, vì vậy chỉ cần hoàn thành Task<T>(với bất kỳ Tvà bất kỳ giá trị nào) và sử dụng nó. Bạn có thể sử dụng một cái gì đó như thế này để che giấu sự thật rằng một kết quả thực tế ở đó, ở đâu đó.

private static Task completedTask = Task.FromResult(false);
public static Task CompletedTask()
{
    return completedTask;
}

Lưu ý rằng vì chúng tôi không để lộ kết quả và tác vụ luôn hoàn thành, chúng tôi có thể lưu trữ một tác vụ duy nhất và sử dụng lại nó.

Nếu bạn đang sử dụng .NET 4.0 và không có FromResultthì bạn có thể tự tạo bằng cách sử dụng TaskCompletionSource:

public static Task<T> FromResult<T>(T value)
{
    var tcs = new TaskCompletionSource<T>();
    tcs.SetResult(value);
    return tcs.Task;
}

8
Nếu bạn đang sử dụng 4.0, bạn có thể thêm thư viện Microsoft.Bcl.Async để nhận TaskEx.FromResult, cũng như những thứ tiện dụng khác như Khi AllAll
Carl

@Servy Nó thay đổi gì từ FromResult (sai) và FromResult (đúng)?
Francesco Bonizzi

3
@FrancescoB. Nếu bạn đã từng nhìn vào kết quả, thì nó sẽ thay đổi giá trị boolean của kết quả. Nếu bạn bỏ qua kết quả, thì kết quả là gì không liên quan.
Phục vụ

66

Phương pháp ưa thích của tôi để làm điều này là gọi Task.WhenAll()mà không có đối số. Các tài liệu MSDN tiểu bang rằng "Nếu mảng đã cung cấp / đếm được chứa không có nhiệm vụ, nhiệm vụ trở lại ngay lập tức sẽ chuyển sang trạng thái RanToCompletion trước khi nó trở về người gọi.". Nghe có vẻ như những gì bạn muốn.

Cập nhật: Tôi đã tìm thấy nguồn trên tại Nguồn tham khảo của Microsoft ; ở đó bạn có thể thấy rằng Task.When ALL chứa các mục sau:

return (tasks.Length == 0) ? // take shortcut if there are no tasks upon which to wait
            Task.CompletedTask :
            new WhenAllPromise(tasks);

Vì vậy, Task.CompletedTask thực sự là nội bộ, nhưng nó được phơi bày bằng cách gọi khi AllAll () không có đối số.


9
Mặc dù nó cảm thấy khó chịu, nhưng nó có sự hỗ trợ từ các tài liệu, vì vậy tôi không biết, tôi rất thích nó!
sara

2
Đối với tôi và mã bị ràng buộc .NET 4.5.2 của tôi, nó đủ thanh lịch. Cảm ơn!
Stas Ivanov

36

Tôi sẽ sử dụng Task.Delay(0). Trong nội bộ, nó trả về một thể hiện được lưu trong bộ nhớ cache của một hoàn thành Task<T>. Đây chính xác là những gì câu trả lời hiện tại đề xuất dù sao đi nữa, chỉ bây giờ bạn không phải tự lưu trữ một cá thể, cũng như bạn không có bất kỳ giá trị rác không phù hợp nào trong mã của mình.

Bạn có thể nghĩ rằng bạn có thể sử dụng Task.Yield()thay vào đó, nhưng nó quay ra kết quả của Task.Yield()không một subtype của Task, trong khi kết quả của Task.Delay(0)là. Đó là một trong những khác biệt tinh tế giữa hai người.


30

Bạn có thể sử dụng Task.FromResult (trong .NET 4.5) để hoàn trả Task<T>.

Nếu bạn cần một cái không chung chung Task, bạn luôn có thể sử dụng Task.FromResult(0)hoặc tương tự, vì Task<T>là một lớp con của Task.


11

Đối với .Net 4.6 trở lên sử dụng

return Task.CompletedTask;

Đối với phiên bản thấp hơn, bạn có thể sử dụng

return new Task(() => { });

3
Đối với phương pháp 4.6 trước, cẩn thận! Bạn cần phải bắt đầu nhiệm vụ hoặc nó sẽ không bao giờ hoàn thành! Làm thế nào về việc sử dụng return Task.Delay(0);thay thế?
Miquel


0

Làm thế nào về:

#pragma warning disable 1998
    public async Task emptyTask() {
    }
#pragma warning restore 1998

Bạn có thể loại bỏ cảnh báo nếu bạn không phiền.


Tôi tin rằng việc đánh dấu một phương thức asyncvẫn tạo ra toàn bộ bộ máy trạng thái ngay cả khi bạn không sử dụng nó, do đó, việc trả về một tác vụ trống sẽ hiệu quả hơn cho các kịch bản tài nguyên thấp.
Calvin Fisher
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.