Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharpNotesForProfessionals.pdf
Скачиваний:
57
Добавлен:
20.05.2023
Размер:
6.12 Mб
Скачать

public static IEnumerable<int> Break()

{

for (int i = 0; ; i++)

{

if (i < 10)

{

// Yields a number yield return i;

}

else

{

// Terminates just the loop break;

}

}

// Execution continues yield return 10;

}

Section 120.11: Return another Enumerable within a method returning Enumerable

public IEnumerable<int> F1()

{

for (int i = 0; i < 3; i++) yield return i;

//return F2(); // Compile Error!! foreach (var element in F2())

yield return element;

}

public int[] F2()

{

return new[] { 3, 4, 5 };

}

GoalKicker.com – C# Notes for Professionals

613

Chapter 121: Task Parallel Library (TPL)

Dataflow Constructs

Section 121.1: ActionBlock<T>

(foreach)

This class can be thought of logically as a bu er for data to be processed combined with tasks for processing that data, with the “dataflow block” managing both. In its most basic usage, we can instantiate an ActionBlock and “post” data to it; the delegate provided at the ActionBlock’s construction will be executed asynchronously for every piece of data posted.

Synchronous Computation

var ab = new ActionBlock<TInput>(i =>

{

Compute(i);

});

ab.Post(1); ab.Post(2); ab.Post(3);

Throttling Asynchronous Downloads to at most 5 concurrently

var downloader = new ActionBlock<string>(async url =>

{

byte [] imageData = await DownloadAsync(url); Process(imageData);

}, new DataflowBlockOptions { MaxDegreeOfParallelism = 5 });

downloader.Post("http://website.com/path/to/images"); downloader.Post("http://another-website.com/path/to/images");

Introduction to TPL Dataflow by Stephen Toub

Section 121.2: BroadcastBlock<T>

(Copy an item and send the copies to every block that it’s linked to)

Unlike Bu erBlock, BroadcastBlock’s mission in life is to enable all targets linked from the block to get a copy of every element published, continually overwriting the “current” value with those propagated to it.

Additionally, unlike Bu erBlock, BroadcastBlock doesn’t hold on to data unnecessarily. After a particular datum has been o ered to all targets, that element will be overwritten by whatever piece of data is next in line (as with all dataflow blocks, messages are handled in FIFO order). That element will be o ered to all targets, and so on.

GoalKicker.com – C# Notes for Professionals

614

Asynchronous Producer/Consumer with a Throttled Producer

var ui = TaskScheduler.FromCurrentSynchronizationContext(); var bb = new BroadcastBlock<ImageData>(i => i);

var saveToDiskBlock = new ActionBlock<ImageData>(item => item.Image.Save(item.Path)

);

var showInUiBlock = new ActionBlock<ImageData>(item => imagePanel.AddImage(item.Image),

new DataflowBlockOptions { TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext() }

);

bb.LinkTo(saveToDiskBlock); bb.LinkTo(showInUiBlock);

Exposing Status from an Agent

public class MyAgent

{

public ISourceBlock<string> Status { get; private set; }

public MyAgent()

{

Status = new BroadcastBlock<string>(); Run();

}

private void Run()

{

Status.Post("Starting"); Status.Post("Doing cool stuff");

Status.Post("Done");

}

}

Introduction to TPL Dataflow by Stephen Toub

Section 121.3: Bu erBlock<T>

(FIFO Queue: The data that comes in is the data that goes out)

In short, Bu erBlock provides an unbounded or bounded bu er for storing instances of T.

You can “post” instances of T to the block, which cause the data being posted to be stored in a first-in-first-out (FIFO) order by the block.

You can “receive” from the block, which allows you to synchronously or asynchronously obtain instances of T previously stored or available in the future (again, FIFO).

GoalKicker.com – C# Notes for Professionals

615

Asynchronous Producer/Consumer with a Throttled Producer

// Hand-off through a bounded BufferBlock<T>

private static BufferBlock<int> _Buffer = new BufferBlock<int>( new DataflowBlockOptions { BoundedCapacity = 10 });

// Producer

private static async void Producer()

{

while(true)

{

await _Buffer.SendAsync(Produce());

}

}

// Consumer

private static async Task Consumer()

{

while(true)

{

Process(await _Buffer.ReceiveAsync());

}

}

// Start the Producer and Consumer private static async Task Run()

{

await Task.WhenAll(Producer(), Consumer());

}

Introduction to TPL Dataflow by Stephen Toub

Section 121.4: JoinBlock<T1, T2,…>

(Collects 2-3 inputs and combines them into a Tuple)

Like BatchBlock, JoinBlock<T1, T2, …> is able to group data from multiple data sources. In fact, that’s JoinBlock<T1, T2, …>’s primary purpose.

For example, a JoinBlock<string, double, int> is an ISourceBlock<Tuple<string, double, int>>.

As with BatchBlock, JoinBlock<T1, T2,…> is capable of operating in both greedy and non-greedy mode.

In the default greedy mode, all data o ered to targets are accepted, even if the other target doesn’t have the necessary data with which to form a tuple.

In non-greedy mode, the block’s targets will postpone data until all targets have been o ered the necessary data to create a tuple, at which point the block will engage in a two-phase commit protocol to atomically retrieve all necessary items from the sources. This postponement makes it possible for another entity to consume the data in the meantime so as to allow the overall system to make forward progress.

GoalKicker.com – C# Notes for Professionals

616