จนถึงตอนนี้ฉันใช้งาน LongRunning TPL สำหรับการทำงานพื้นหลังที่ถูกผูกไว้กับซีพียูแบบวนรอบแทนการจับเวลาเธรดเนื่องจาก:
- งาน TPL รองรับการยกเลิก
- ตัวจับเวลาเธรดสามารถเริ่มเธรดอื่นได้ในขณะที่โปรแกรมกำลังปิดตัวลงทำให้เกิดปัญหากับทรัพยากรที่ถูกกำจัด
- โอกาสในการโอเวอร์รัน: ตัวจับเวลาเธรดสามารถเริ่มเธรดอื่นได้ในขณะที่ก่อนหน้านี้ยังคงถูกประมวลผลเนื่องจากการทำงานที่ยาวนานโดยไม่คาดคิด (ฉันรู้ว่าสามารถป้องกันได้โดยการหยุดและรีสตาร์ทตัวจับเวลา)
อย่างไรก็ตามโซลูชัน TPL จะอ้างสิทธิ์เธรดเฉพาะเสมอซึ่งไม่จำเป็นในขณะที่รอการดำเนินการถัดไป (ซึ่งส่วนใหญ่แล้ว) ฉันต้องการใช้โซลูชันที่เสนอของเจฟฟ์เพื่อทำงานแบบวนรอบของ CPU บนพื้นหลังเพราะมันต้องการเธรดพูลเธรดเมื่อมีงานที่ต้องทำซึ่งดีกว่าสำหรับความสามารถในการปรับขนาดได้ (โดยเฉพาะอย่างยิ่งเมื่อช่วงเวลามีขนาดใหญ่)
เพื่อให้บรรลุเป้าหมายนี้ฉันขอแนะนำการดัดแปลง 4 ประการ:
- เพิ่ม
ConfigureAwait(false)
ลงในTask.Delay()
การดำเนินdoWork
การกับเธรดพูลเธรดมิฉะนั้นdoWork
จะดำเนินการกับเธรดการเรียกซึ่งไม่ใช่แนวคิดของการขนานกัน
- ยึดติดกับรูปแบบการยกเลิกโดยการโยน TaskCanceledException (ยังจำเป็น?)
- ส่งต่อ Can CancelToken ไปที่
doWork
เพื่อเปิดใช้งานเพื่อยกเลิกงาน
- เพิ่มพารามิเตอร์ของวัตถุชนิดเพื่อจัดหาข้อมูลสถานะงาน (เช่นงาน TPL)
เกี่ยวกับจุดที่ 2 ฉันไม่แน่ใจว่า async รอคอยยังคงต้องการ TaskCanceledExecption อยู่หรือไม่หรือเป็นเพียงแนวทางปฏิบัติที่ดีที่สุด
public static async Task Run(Action<object, CancellationToken> doWork, object taskState, TimeSpan period, CancellationToken cancellationToken)
{
do
{
await Task.Delay(period, cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
doWork(taskState, cancellationToken);
}
while (true);
}
กรุณาแสดงความคิดเห็นของคุณเกี่ยวกับแนวทางแก้ไขที่เสนอ ...
อัปเดต 2016-8-30
การแก้ปัญหาดังกล่าวข้างต้นไม่ได้ทันทีโทรdoWork()
แต่เริ่มต้นด้วยเพื่อให้เกิดการสลับด้ายสำหรับawait Task.Delay().ConfigureAwait(false)
doWork()
วิธีแก้ปัญหาด้านล่างนี้จะเอาชนะปัญหานี้ได้โดยการตัดdoWork()
สายแรกเข้าTask.Run()
และรอสาย
ด้านล่างนี้คือ async \ await ที่ได้รับการปรับปรุงใหม่สำหรับThreading.Timer
การทำงานที่สามารถยกเลิกได้และสามารถปรับขนาดได้ (เมื่อเทียบกับโซลูชัน TPL) เนื่องจากไม่ได้ใช้เธรดใด ๆ ในขณะที่รอการดำเนินการถัดไป
โปรดทราบว่าในทางตรงกันข้ามกับ Timer เวลาที่รอ ( period
) จะคงที่และไม่ใช่รอบเวลา รอบเวลาคือผลรวมของเวลารอคอยและระยะเวลาdoWork()
ที่อาจแตกต่างกันไป
public static async Task Run(Action<object, CancellationToken> doWork, object taskState, TimeSpan period, CancellationToken cancellationToken)
{
await Task.Run(() => doWork(taskState, cancellationToken), cancellationToken).ConfigureAwait(false);
do
{
await Task.Delay(period, cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
doWork(taskState, cancellationToken);
}
while (true);
}