// This is a modification of Stephen Toub's Pipelines // example from Patterns Of Parallel Programming. private static async Task RunPipeline(VReader vreader, long totalframes) { var rawFrames = new BlockingCollection <Bitmap>(); var processedFrames = new BlockingCollection <Bitmap>(); // Stage 1: read raw frames. var readTask = Task.Run(() => { try { for (long n = 0; n < totalframes; n++) { rawFrames.Add(vreader.ReadVideoFrame()); } } finally { rawFrames.CompleteAdding(); } }); // Stage 2: process frames in parallel. var processTask = Task.Run(async() => { try { var degreesOfParallellism = Environment.ProcessorCount; var consumingEnumerable = rawFrames.GetConsumingEnumerable(); // Start our parallel tasks. while (true) { var tasks = consumingEnumerable .Take(degreesOfParallellism) .Select(frame => Task.Run(() => { Process(frame); return(frame); })) .ToArray(); if (tasks.Length == 0) { break; } await Task.WhenAll(tasks); foreach (var t in tasks) { processedFrames.Add(t.Result); } } } finally { processedFrames.CompleteAdding(); } }); // Stage 3: write results to file and dispose of the frame. var writeTask = Task.Run(() => { foreach (var processedFrame in processedFrames.GetConsumingEnumerable()) { FrameFile.Add(processedFrame.ID); processedFrame.Dispose(); } }); await Task.WhenAll(readTask, processTask, writeTask); }
// Sequential implementation - as is (for comparison). private static void RunSequential(VReader vreader, long totalframes) { for (long n = 0; n < totalframes; n++) { using (Bitmap frame = vreader.ReadVideoFrame()) { Process(frame); WriteToFile(frame); } } }
// This is a modification of Stephen Toub's Pipelines // example from Patterns Of Parallel Programming. private static void RunPipeline(VReader vreader, long totalframes) { var rawFrames = new BlockingCollection <Bitmap>(); var processedFrames = new BlockingCollection <Bitmap>(); // Stage 1: read raw frames. var readTask = Task.Run(() => { try { for (long n = 0; n < totalframes; n++) { rawFrames.Add(vreader.ReadVideoFrame()); } } finally { rawFrames.CompleteAdding(); } }); // Stage 2: process frames in parallel. var processTask = Task.Run(() => { try { // Try both - see which performs better in your scenario. Step2WithParallelTasks(rawFrames, processedFrames); //Step2WithPLinq(rawFrames, processedFrames); } finally { processedFrames.CompleteAdding(); } }); // Stage 3: write results to file and dispose of the frame. var writeTask = Task.Run(() => { foreach (var processedFrame in processedFrames.GetConsumingEnumerable()) { WriteToFile(processedFrame); processedFrame.Dispose(); } }); Task.WaitAll(readTask, processTask, writeTask); }
// This is a modification of Stephen Toub's Pipelines // example from Patterns Of Parallel Programming. private static async Task RunPipeline(VReader vreader, long totalframes) { var rawFrames = new BlockingCollection <Bitmap>(); var processedFrames = new BlockingCollection <Bitmap>(); // Stage 1. var readTask = Task.Run(() => { try { for (long n = 0; n < totalframes; n++) { rawFrames.Add(vreader.ReadVideoFrame()); } } finally { rawFrames.CompleteAdding(); } }); // Stage 2. var processTask = Task.Run(() => { try { foreach (var frame in rawFrames.GetConsumingEnumerable()) { Process(frame); processedFrames.Add(frame); } } finally { processedFrames.CompleteAdding(); } }); // Stage 3. var writeTask = Task.Run(() => { FrameFile.AddRange(processedFrames.GetConsumingEnumerable().Select(f => f.ID)); }); await Task.WhenAll(readTask, processTask, writeTask); }