มีกฎที่ดีหรือไม่ที่จะใช้งานTaskDelayกับThread.Sleepเมื่อใด
- โดยเฉพาะมีค่าต่ำสุดที่จะให้เพื่อให้มีประสิทธิภาพ / มีประสิทธิภาพเหนืออื่น ๆ ?
- สุดท้ายเนื่องจาก Task.Delay ทำให้เกิดการสลับบริบทบนเครื่อง async / await มีค่าใช้จ่ายหรือไม่
มีกฎที่ดีหรือไม่ที่จะใช้งานTaskDelayกับThread.Sleepเมื่อใด
คำตอบ:
ใช้Thread.Sleep
เมื่อคุณต้องการบล็อกเธรดปัจจุบัน
ใช้Task.Delay
เมื่อคุณต้องการความล่าช้าแบบลอจิคัลโดยไม่ปิดกั้นเธรดปัจจุบัน
ประสิทธิภาพไม่ควรกังวลอย่างยิ่งกับวิธีการเหล่านี้ การใช้งานจริงของโลกหลักของพวกเขาคือลองใช้ตัวจับเวลาซ้ำสำหรับการดำเนินการ I / O ซึ่งอยู่ในลำดับวินาทีมากกว่ามิลลิวินาที
Thread.Sleep
จะบล็อกเธรดปัจจุบันซึ่งทำให้เกิดการสลับบริบท หากคุณใช้พูลเธรดนี่อาจทำให้เธรดใหม่ได้รับการจัดสรร การดำเนินการทั้งสองค่อนข้างหนักในขณะที่การทำงานแบบมัลติทาสกิ้งที่จัดทำโดยTask.Delay
ฯลฯ ได้รับการออกแบบมาเพื่อหลีกเลี่ยงค่าใช้จ่ายทั้งหมดเพิ่มปริมาณงานให้มากที่สุดอนุญาตให้ยกเลิกและให้รหัสที่ชัดเจนขึ้น
onesi: I would use
Thread.Sleep` เพื่อรอวิธีการแบบซิงโครนัส อย่างไรก็ตามฉันไม่เคยทำเช่นนี้ในรหัสการผลิต; จากประสบการณ์ของฉันทุกคนที่Thread.Sleep
ฉันเคยเห็นได้บ่งบอกถึงปัญหาการออกแบบบางประเภทที่ต้องได้รับการแก้ไขอย่างเหมาะสม
ความแตกต่างที่ใหญ่ที่สุดระหว่างTask.Delay
และThread.Sleep
นั่นTask.Delay
ก็เพื่อให้ทำงานแบบอะซิงโครนัส มันไม่สมเหตุสมผลที่จะใช้Task.Delay
ในรหัสซิงโครนัส มันเป็นความคิดที่ดีมากที่จะใช้Thread.Sleep
ในโค้ดแบบอะซิงโครนัส
โดยปกติแล้วคุณจะโทรหาTask.Delay()
ด้วยawait
คำหลัก:
await Task.Delay(5000);
หรือถ้าคุณต้องการเรียกใช้รหัสบางอย่างก่อนที่จะล่าช้า:
var sw = new Stopwatch();
sw.Start();
Task delay = Task.Delay(5000);
Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds);
await delay;
คาดเดาสิ่งที่จะพิมพ์นี้ วิ่งเป็นเวลา 0.0070048 วินาที ถ้าเราย้ายawait delay
ข้างบนConsole.WriteLine
แทนมันจะพิมพ์ทำงานเป็นเวลา 5.0020168 วินาที
ลองดูความแตกต่างด้วยThread.Sleep
:
class Program
{
static void Main(string[] args)
{
Task delay = asyncTask();
syncCode();
delay.Wait();
Console.ReadLine();
}
static async Task asyncTask()
{
var sw = new Stopwatch();
sw.Start();
Console.WriteLine("async: Starting");
Task delay = Task.Delay(5000);
Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds);
await delay;
Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds);
Console.WriteLine("async: Done");
}
static void syncCode()
{
var sw = new Stopwatch();
sw.Start();
Console.WriteLine("sync: Starting");
Thread.Sleep(5000);
Console.WriteLine("sync: Running for {0} seconds", sw.Elapsed.TotalSeconds);
Console.WriteLine("sync: Done");
}
}
พยายามทำนายสิ่งที่จะพิมพ์ ...
async: การเริ่มต้น
async: การทำงานสำหรับการ
ซิงค์0.0070048 วินาที: การเริ่มต้น
async: การทำงานสำหรับ 5.0119008 วินาที
async: เสร็จสิ้นการ
ซิงค์: ทำงานสำหรับการ
ซิงค์5.0020168 วินาที: เสร็จแล้ว
นอกจากนี้ยังเป็นที่น่าสนใจที่จะสังเกตว่าThread.Sleep
มีความแม่นยำมากกว่านั้นความแม่นยำของ ms ไม่ใช่ปัญหาจริงๆในขณะที่Task.Delay
ใช้เวลาน้อยที่สุด 15-30ms ค่าใช้จ่ายของทั้งสองฟังก์ชั่นนั้นน้อยมากเมื่อเทียบกับความแม่นยำของ ms ที่มี (ใช้Stopwatch
คลาสถ้าคุณต้องการบางอย่างที่แม่นยำกว่า) Thread.Sleep
ยังคงผูกด้ายของคุณTask.Delay
ปล่อยมันไปทำงานอื่น ๆ ในขณะที่คุณรอ
Thread.Sleep()
ใช้ทั้งเธรดซึ่งสามารถใช้ที่อื่นได้ หากงานจำนวนมากรันด้วย Thread.Sleep () มีโอกาสสูงที่จะหมดเธรดพูลเธรดทั้งหมดและขัดขวางประสิทธิภาพการทำงานอย่างจริงจัง
async
วิธีการที่พวกเขาได้รับการสนับสนุนให้ใช้ เป็นเพียงความคิดที่ไม่ดีที่จะเรียกใช้Thread.Sleep()
ในเธรดพูลด้ายไม่ใช่ความคิดที่ไม่ดีโดยทั่วไป หลังจากที่ทุกคนมีTaskCreationOptions.LongRunning
เมื่อการไป (แม้จะท้อแท้) Task.Factory.StartNew()
เส้นทาง
await wait
Tasl.Delay
ใช้ตัวจับเวลาระบบ ตั้งแต่ "นาฬิกาของระบบ" ติ๊ก "ที่อัตราคงที่" ความเร็วของติ๊กของตัวจับเวลาระบบจะอยู่ที่ประมาณ 16ms ความล่าช้าใด ๆ ที่คุณร้องขอจะถูกปัดเศษเป็นจำนวนของสัญญาณของนาฬิการะบบถูกชดเชยด้วยเวลาจนถึงครั้งแรก เห็บ ดูเอกสารประกอบของTask.Delay
msdnในdocs.microsoft.com/en-us/dotnet/api/…และเลื่อนลงไปที่หมายเหตุ
ถ้าเธรดปัจจุบันถูกฆ่าตายและคุณใช้และจะมีการดำเนินการแล้วคุณอาจได้รับThread.Sleep
ThreadAbortException
ด้วยTask.Delay
คุณสามารถให้โทเค็นการยกเลิกและฆ่ามันได้อย่างสง่างาม Thats Task.Delay
เหตุผลหนึ่งที่ผมจะเลือก ดูhttp://social.technet.microsoft.com/wiki/contents/articles/21177.visual-c-thread-sleep-vs-task-delay.aspx
ฉันเห็นด้วยกับประสิทธิภาพที่ไม่สำคัญยิ่งในกรณีนี้
await Task.Delay(5000)
. เมื่อฉันฆ่าภารกิจที่ฉันได้รับTaskCanceledException
(และปราบปราม) แต่หัวข้อของฉันยังมีชีวิตอยู่ เรียบร้อย! :)
ฉันต้องการเพิ่มบางสิ่ง จริงๆแล้วTask.Delay
มันเป็นกลไกการรอตามเวลา หากคุณดูที่แหล่งที่มาคุณจะพบการอ้างอิงไปยังTimer
คลาสที่รับผิดชอบความล่าช้า ในทางกลับกันThread.Sleep
ทำให้เธรดปัจจุบันเข้าสู่โหมดสลีในแบบที่คุณเป็นเพียงการบล็อกและการสูญเสียเธรดหนึ่ง ในรูปแบบการเขียนโปรแกรม async คุณควรใช้Task.Delay()
ถ้าคุณต้องการบางสิ่งบางอย่าง (ต่อเนื่อง) เกิดขึ้นหลังจากความล่าช้า