หากคุณไม่ต้องการใช้ async / await ในวิธีการของคุณ แต่ยังคง "ตกแต่ง" เพื่อให้สามารถใช้คำหลักที่รอคอยจากภายนอกTaskCompletionSource.cs :
public static Task<T> RunAsync<T>(Func<T> function)
{
if (function == null) throw new ArgumentNullException(“function”);
var tcs = new TaskCompletionSource<T>();
ThreadPool.QueueUserWorkItem(_ =>
{
try
{
T result = function();
tcs.SetResult(result);
}
catch(Exception exc) { tcs.SetException(exc); }
});
return tcs.Task;
}
จากที่นี่และที่นี่
เพื่อสนับสนุนกระบวนทัศน์ดังกล่าวกับ Tasks เราจำเป็นต้องมีวิธีในการรักษาส่วนหน้าของงานและความสามารถในการอ้างถึงการดำเนินการแบบอะซิงโครนัสโดยพลการในฐานะงาน แต่เพื่อควบคุมอายุการใช้งานของงานนั้นตามกฎของ อะซิงโครนัสและต้องทำในลักษณะที่ไม่เสียค่าใช้จ่ายมากนัก นี่คือจุดประสงค์ของ TaskCompletionSource
ฉันเห็นยังใช้ใน. NET แหล่งเช่น WebClient.cs :
[HostProtection(ExternalThreading = true)]
[ComVisible(false)]
public Task<string> UploadStringTaskAsync(Uri address, string method, string data)
{
// Create the task to be returned
var tcs = new TaskCompletionSource<string>(address);
// Setup the callback event handler
UploadStringCompletedEventHandler handler = null;
handler = (sender, e) => HandleCompletion(tcs, e, (args) => args.Result, handler, (webClient, completion) => webClient.UploadStringCompleted -= completion);
this.UploadStringCompleted += handler;
// Start the async operation.
try { this.UploadStringAsync(address, method, data, tcs); }
catch
{
this.UploadStringCompleted -= handler;
throw;
}
// Return the task that represents the async operation
return tcs.Task;
}
ในที่สุดฉันก็พบว่ามีประโยชน์เช่นกัน:
ฉันถูกถามคำถามนี้ตลอดเวลา ความหมายคือต้องมีเธรดบางแห่งที่บล็อกในการโทร I / O ไปยังทรัพยากรภายนอก ดังนั้นรหัสแบบอะซิงโครนัสทำให้เธรดร้องขอเพิ่มขึ้น แต่มีค่าใช้จ่ายของเธรดอื่นที่อื่นในระบบใช่ไหม ไม่เลย. เพื่อให้เข้าใจว่าทำไมขนาดคำขอแบบอะซิงโครนัสฉันจะติดตามตัวอย่าง (ตัวย่อ) ของการโทรแบบ I / O แบบอะซิงโครนัส สมมติว่าคำขอต้องเขียนไปยังไฟล์ เธรดคำร้องขอเรียกวิธีการเขียนแบบอะซิงโครนัส WriteAsync ดำเนินการโดย Base Class Library (BCL) และใช้พอร์ตที่สมบูรณ์สำหรับ I / O แบบอะซิงโครนัส ดังนั้นการเรียกใช้ WriteAsync จึงถูกส่งผ่านไปยัง OS เพื่อเขียนไฟล์อะซิงโครนัส จากนั้นระบบปฏิบัติการจะสื่อสารกับไดรเวอร์สแต็คส่งผ่านข้อมูลเพื่อเขียนใน I / O Request packet (IRP) นี่คือสิ่งที่น่าสนใจ: หากไดรเวอร์อุปกรณ์ไม่สามารถจัดการ IRP ได้ทันทีจะต้องจัดการแบบอะซิงโครนัส ดังนั้นไดรเวอร์บอกให้ดิสก์เริ่มเขียนและส่งกลับการตอบสนอง“ รอดำเนินการ” ไปยังระบบปฏิบัติการ ระบบปฏิบัติการผ่านการตอบสนอง“ ที่รอดำเนินการ” ไปยัง BCL และ BCL ส่งคืนงานที่ไม่สมบูรณ์ไปยังรหัสการจัดการคำขอ รหัสการจัดการการร้องขอกำลังรองานซึ่งจะส่งคืนงานที่ไม่สมบูรณ์จากวิธีการนั้นเป็นต้น ในที่สุดรหัสการจัดการการร้องขอจะจบลงด้วยการส่งคืนงานที่ไม่สมบูรณ์ไปยัง ASP.NET และเธรดการร้องขอนั้นจะถูกปล่อยให้กลับไปยังพูลเธรด รหัสการจัดการการร้องขอกำลังรองานซึ่งจะส่งคืนงานที่ไม่สมบูรณ์จากวิธีการนั้นเป็นต้น ในที่สุดรหัสการจัดการการร้องขอจะจบลงด้วยการส่งคืนงานที่ไม่สมบูรณ์ไปยัง ASP.NET และเธรดการร้องขอนั้นจะถูกปล่อยให้กลับไปยังพูลเธรด รหัสการจัดการการร้องขอกำลังรองานซึ่งจะส่งคืนงานที่ไม่สมบูรณ์จากวิธีการนั้นเป็นต้น ในที่สุดรหัสการจัดการการร้องขอจะจบลงด้วยการส่งคืนงานที่ไม่สมบูรณ์ไปยัง ASP.NET และเธรดการร้องขอนั้นจะถูกปล่อยให้กลับไปยังพูลเธรด
บทนำสู่ Async / Await บน ASP.NET
หากเป้าหมายคือการปรับปรุงความสามารถในการขยาย (มากกว่าการตอบสนอง) เป้าหมายทั้งหมดนั้นขึ้นอยู่กับการมีอยู่ของ I / O ภายนอกที่ให้โอกาสในการทำเช่นนั้น