פתרון pipeline שנכשל¶
העברת הבעלות תתבצע רק אחרי ש־WriteAsync הצליח. קטע הקוד הבא מחליף את גוף יצירת הפריט במפיק, כאשר writer הוא ChannelWriter
Item? owned = new Item(value);
try
{
await writer.WriteAsync(owned, token);
owned = null;
}
finally { owned?.Dispose(); }
הצרכן משתמש ב־using על הפריט מיד לאחר הקריאה. אחרי WhenAll, ובתוך finally שמתרחש לאחר ששתי המשימות הגיעו למצב סופי, נרוקן באמצעות TryRead ונשחרר כל פריט שנותר. אין לבצע ניקוי סופי כל עוד מפיק יכול להוסיף פריט חדש. במערכת הזאת יש צרכן אחד, ולכן אין סכנה שפעולת הניקוי תתחרה עם consumer חי אחרי שהצטרפנו אליו.
הדוגמה הבאה עצמאית ומדגימה את ההבדל בין timeout להשלמה. היא ממתינה בסוף לפעולה המקורית כדי לא להשאיר עבודה בלתי נצפית.
Task<int> operation = Work();
try { Console.WriteLine(await operation.WaitAsync(TimeSpan.FromMilliseconds(5))); }
catch (TimeoutException) { Console.WriteLine("wait timed out"); }
Console.WriteLine($"eventual result={await operation}");
static async Task<int> Work()
{
await Task.Delay(100);
return 42;
}
ה־Dispose של מקור הביטול משחרר את משאביו ואינו מחליף Cancel. גם Cancel אינו מצטרף אוטומטית לפעולה. הבדיקה עם capacity של 1 חשובה משום שהיא מגדילה את הסיכוי שהמפיק נמצא בהמתנה בדיוק בזמן שהצרכן נכשל, וכך חושפת מסלול שבו שכחנו להפיץ את הביטול.