สร้างภารกิจที่เสร็จสมบูรณ์


197

ฉันต้องการที่จะสร้างเสร็จสมบูรณ์Task(ไม่Task<T>) มีบางอย่างใน. NET ที่จะทำเช่นนี้?

คำถามที่เกี่ยวข้อง: สร้างภารกิจที่เสร็จสมบูรณ์ <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.คุณคิดว่าปัญหานี้มีปัญหาอะไร หากคุณแคชเพียงครั้งเดียวTaskโปรแกรมทั้งหมดของคุณจะใช้หน่วยความจำเพิ่มอีกหนึ่งบิต นั่นคืออะไร นอกจากนี้หนึ่งสามารถสร้างงานที่เสร็จสมบูรณ์โดยไม่ทำอย่างนั้นมันก็จะไม่ดีขึ้น
Servy

10
โอ้ความผิดหวังของฉันไม่มีส่วนเกี่ยวข้องกับการใช้หน่วยความจำเพิ่มเติม เป็นเพียงแค่ค่าขยะที่ใดก็ได้ในรหัสไม่ได้สวยงาม
Timothy Shields

1
โปรดทราบว่าวันนี้มีValueTaskงานที่เสร็จสมบูรณ์แล้ว (เช่นค่าที่คุณมีอยู่แล้วเพื่อให้รหัสนั้นเป็นแบบซิงโครนัส) ซึ่งจะช่วยให้คุณประหยัดการจัดสรร
nawfal

คำตอบ:


247

รุ่นใหม่ล่าสุดของสุทธิ (v4.6)คือการเพิ่มเพียงแค่นั้นในตัวTask.CompletedTask :

Task completedTask = Task.CompletedTask;

คุณสมบัตินั้นถูกนำมาใช้เป็นซิงเกิลที่ไม่ล็อคดังนั้นคุณจะใช้งานที่เสร็จสมบูรณ์เหมือนกันเกือบตลอดเวลา


1
เพิ่งตรวจสอบ VS 14 CTP ล่าสุดและสร้างโครงการ 4.5.3 Task.CompletedTaskยังคงเป็นภายใน
Peter Ritchie

1
2. อาจเป็นเพราะคุณยังไม่ได้ดาวน์โหลด CTP ล่าสุด (ซึ่งคือ 4 และเชื่อมโยงกับจากไซต์นั้น) หรือคุณไม่ได้ระบุรุ่น 4.5.3 นี่คือสิ่งที่อยู่บนเครื่องของฉัน @PeterRitchie
i3arnon

ฉันสร้าง VM จากอิมเมจ Visual Studio 14 บน Azure
Peter Ritchie


ฉันกำลังทำงานกับ Mac OS X ด้วยโมโน 5.4.1.7 และฉันได้รับข้อผิดพลาดเดียวกันนี้ ฉันจะแก้ไขสิ่งนี้ได้อย่างไร
Khaled Annajar

153

Task<T>สามารถแปลงเป็นปริยายได้Taskดังนั้นเพียงแค่ทำให้เสร็จสมบูรณ์Task<T>(มีTค่าใด ๆ และค่าใด ๆ ) และใช้สิ่งนั้น คุณสามารถใช้สิ่งนี้เพื่อซ่อนความจริงที่ว่าผลลัพธ์ที่แท้จริงอยู่ที่นั่นที่ไหนสักแห่ง

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

โปรดทราบว่าเนื่องจากเราไม่ได้เปิดเผยผลลัพธ์และงานนั้นเสร็จสมบูรณ์เสมอเราสามารถแคชงานเดียวและนำมาใช้ซ้ำได้

หากคุณใช้. NET 4.0 และยังไม่มีFromResultคุณสามารถสร้างของคุณเองโดยใช้TaskCompletionSource:

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

8
หากคุณใช้ 4.0 คุณสามารถเพิ่มไลบรารี Microsoft.Bcl.Async เพื่อรับ TaskEx.FromResult รวมถึงสิ่งที่มีประโยชน์อื่น ๆ เช่น WhenAll
Carl

@Servy มันเปลี่ยนจาก FromResult (false) และ FromResult (จริง) คืออะไร?
Francesco Bonizzi

3
@FrancescoB หากคุณเคยดูผลลัพธ์มันจะเปลี่ยนค่าบูลีนของผลลัพธ์ หากคุณไม่สนใจผลลัพธ์สิ่งที่ผลลัพธ์นั้นไม่เกี่ยวข้อง
Servy

66

วิธีที่ฉันชอบในการทำเช่นนี้คือโทรTask.WhenAll()โดยไม่มีข้อโต้แย้ง MSDN เอกสารระบุว่า "ถ้าจัดอาร์เรย์ / นับมีงานไม่มีงานที่ส่งกลับจะเปลี่ยนแปลงทันทีไปยังรัฐ RanToCompletion ก่อนที่จะกลับไปยังผู้โทร." ฟังดูเหมือนสิ่งที่คุณต้องการ

อัปเดต: ฉันพบแหล่งที่มาที่แหล่งอ้างอิงของ Microsoft ; ที่นั่นคุณจะเห็นว่า Task.WhenAll มีสิ่งต่อไปนี้:

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

ดังนั้น Task.CompletedTask จึงเป็น Internal แต่จะถูกเปิดเผยโดยการเรียก WhenAll () โดยไม่มีอาร์กิวเมนต์


9
ในขณะที่มันรู้สึกแฮ็คมันได้รับการสนับสนุนจากเอกสารดังนั้นฉันจึงไม่รู้ฉันชอบมัน!
sara

2
สำหรับฉันและ. NET 4.5.2 รหัสที่ จำกัด ของฉันมันก็สง่างามพอ ขอบคุณ!
Stas Ivanov

36

Task.Delay(0)ผมจะใช้ Task<T>ภายในก็จะส่งกลับอินสแตนซ์แคชเสร็จ นี่คือสิ่งที่คำตอบปัจจุบันแนะนำให้ทำต่อไปเพียงแค่ตอนนี้คุณไม่ต้องแคชอินสแตนซ์ด้วยตัวคุณเองและคุณไม่มีค่าขยะที่ไม่เหมาะสมในรหัสของคุณ

คุณอาจจะคิดว่าคุณสามารถใช้Task.Yield()แทน แต่มันกลับกลายเป็นผลจากการTask.Yield()เป็นไม่ย่อยของTaskในขณะที่ผลจากการTask.Delay(0)มี นั่นเป็นหนึ่งในความแตกต่างที่ลึกซึ้งระหว่างสองคนนี้


30

คุณสามารถใช้Task.FromResult (ใน .NET 4.5) Task<T>เพื่อกลับเสร็จ

หากคุณต้องการที่ไม่ใช่ทั่วไปTask, คุณสามารถใช้Task.FromResult(0)หรือคล้ายกันเนื่องจากTask<T>เป็น subclass Taskของ


11

สำหรับการใช้. Net 4.6 ขึ้นไป

return Task.CompletedTask;

สำหรับรุ่นที่ต่ำกว่าคุณสามารถใช้

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

3
สำหรับวิธี 4.6 ก่อนระวัง! คุณต้องเริ่มงานมิฉะนั้นจะไม่สำเร็จ! วิธีการเกี่ยวกับการใช้return Task.Delay(0);แทน?
Miquel


0

เกี่ยวกับ:

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

คุณสามารถละทิ้งคำเตือนหากคุณไม่รังเกียจ


ฉันเชื่อว่าการทำเครื่องหมายวิธีasyncยังคงสร้างเครื่องมือเครื่องรัฐทั้งหมดแม้ว่าคุณจะไม่ได้ใช้งานดังนั้นการส่งคืนงานเปล่าจะมีประสิทธิภาพมากขึ้นสำหรับสถานการณ์ทรัพยากรต่ำ
Calvin Fisher
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.