// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // // DataflowBlockOptions.cs // // // DataflowBlockOptions types for configuring dataflow blocks // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- using System; using System.Diagnostics; using System.Threading.Tasks; namespace System.Threading.Tasks.Dataflow { /// /// Provides options used to configure the processing performed by dataflow blocks. /// /// /// is mutable and can be configured through its properties. /// When specific configuration options are not set, the following defaults are used: /// /// /// Options /// Default /// /// /// TaskScheduler /// /// /// /// MaxMessagesPerTask /// DataflowBlockOptions.Unbounded (-1) /// /// /// CancellationToken /// /// /// /// BoundedCapacity /// DataflowBlockOptions.Unbounded (-1) /// /// /// NameFormat /// "{0} Id={1}" /// /// /// Dataflow blocks capture the state of the options at their construction. Subsequent changes /// to the provided instance should not affect the behavior /// of a dataflow block. /// [DebuggerDisplay("TaskScheduler = {TaskScheduler}, MaxMessagesPerTask = {MaxMessagesPerTask}, BoundedCapacity = {BoundedCapacity}")] public class DataflowBlockOptions { /// /// A constant used to specify an unlimited quantity for members /// that provide an upper bound. This field is constant. /// public const Int32 Unbounded = -1; /// The scheduler to use for scheduling tasks to process messages. private TaskScheduler _taskScheduler = TaskScheduler.Default; /// The cancellation token to monitor for cancellation requests. private CancellationToken _cancellationToken = CancellationToken.None; /// The maximum number of messages that may be processed per task. private Int32 _maxMessagesPerTask = Unbounded; /// The maximum number of messages that may be buffered by the block. private Int32 _boundedCapacity = Unbounded; /// The name format to use for creating a name for a block. private string _nameFormat = "{0} Id={1}"; // see NameFormat property for a description of format items /// A default instance of . /// /// Do not change the values of this instance. It is shared by all of our blocks when no options are provided by the user. /// internal static readonly DataflowBlockOptions Default = new DataflowBlockOptions(); /// Returns this instance if it's the default instance or else a cloned instance. /// An instance of the options that may be cached by the block. internal DataflowBlockOptions DefaultOrClone() { return (this == Default) ? this : new DataflowBlockOptions { TaskScheduler = this.TaskScheduler, CancellationToken = this.CancellationToken, MaxMessagesPerTask = this.MaxMessagesPerTask, BoundedCapacity = this.BoundedCapacity, NameFormat = this.NameFormat }; } /// Initializes the . public DataflowBlockOptions() { } /// Gets or sets the to use for scheduling tasks. public TaskScheduler TaskScheduler { get { return _taskScheduler; } set { Debug.Assert(this != Default, "Default instance is supposed to be immutable."); if (value == null) throw new ArgumentNullException("value"); _taskScheduler = value; } } /// Gets or sets the to monitor for cancellation requests. public CancellationToken CancellationToken { get { return _cancellationToken; } set { Debug.Assert(this != Default, "Default instance is supposed to be immutable."); _cancellationToken = value; } } /// Gets or sets the maximum number of messages that may be processed per task. public Int32 MaxMessagesPerTask { get { return _maxMessagesPerTask; } set { Debug.Assert(this != Default, "Default instance is supposed to be immutable."); if (value < 1 && value != Unbounded) throw new ArgumentOutOfRangeException("value"); _maxMessagesPerTask = value; } } /// Gets a MaxMessagesPerTask value that may be used for comparison purposes. /// The maximum value, usable for comparison purposes. /// Unlike MaxMessagesPerTask, this property will always return a positive value. internal Int32 ActualMaxMessagesPerTask { get { return (_maxMessagesPerTask == Unbounded) ? Int32.MaxValue : _maxMessagesPerTask; } } /// Gets or sets the maximum number of messages that may be buffered by the block. public Int32 BoundedCapacity { get { return _boundedCapacity; } set { Debug.Assert(this != Default, "Default instance is supposed to be immutable."); if (value < 1 && value != Unbounded) throw new ArgumentOutOfRangeException("value"); _boundedCapacity = value; } } /// /// Gets or sets the format string to use when a block is queried for its name. /// /// /// The name format may contain up to two format items. {0} will be substituted /// with the block's name. {1} will be substituted with the block's Id, as is /// returned from the block's Completion.Id property. /// public string NameFormat { get { return _nameFormat; } set { Debug.Assert(this != Default, "Default instance is supposed to be immutable."); if (value == null) throw new ArgumentNullException("value"); _nameFormat = value; } } } /// /// Provides options used to configure the processing performed by dataflow blocks that /// process each message through the invocation of a user-provided delegate, blocks such /// as and . /// /// /// is mutable and can be configured through its properties. /// When specific configuration options are not set, the following defaults are used: /// /// /// Options /// Default /// /// /// TaskScheduler /// /// /// /// CancellationToken /// /// /// /// MaxMessagesPerTask /// DataflowBlockOptions.Unbounded (-1) /// /// /// BoundedCapacity /// DataflowBlockOptions.Unbounded (-1) /// /// /// NameFormat /// "{0} Id={1}" /// /// /// MaxDegreeOfParallelism /// 1 /// /// /// SingleProducerConstrained /// false /// /// /// Dataflow block captures the state of the options at their construction. Subsequent changes /// to the provided instance should not affect the behavior /// of a dataflow block. /// [DebuggerDisplay("TaskScheduler = {TaskScheduler}, MaxMessagesPerTask = {MaxMessagesPerTask}, BoundedCapacity = {BoundedCapacity}, MaxDegreeOfParallelism = {MaxDegreeOfParallelism}")] public class ExecutionDataflowBlockOptions : DataflowBlockOptions { /// A default instance of . /// /// Do not change the values of this instance. It is shared by all of our blocks when no options are provided by the user. /// internal new static readonly ExecutionDataflowBlockOptions Default = new ExecutionDataflowBlockOptions(); /// Returns this instance if it's the default instance or else a cloned instance. /// An instance of the options that may be cached by the block. internal new ExecutionDataflowBlockOptions DefaultOrClone() { return (this == Default) ? this : new ExecutionDataflowBlockOptions { TaskScheduler = this.TaskScheduler, CancellationToken = this.CancellationToken, MaxMessagesPerTask = this.MaxMessagesPerTask, BoundedCapacity = this.BoundedCapacity, NameFormat = this.NameFormat, MaxDegreeOfParallelism = this.MaxDegreeOfParallelism, SingleProducerConstrained = this.SingleProducerConstrained }; } /// The maximum number of tasks that may be used concurrently to process messages. private Int32 _maxDegreeOfParallelism = 1; /// Whether the code using this block will only ever have a single producer accessing the block at any given time. private Boolean _singleProducerConstrained = false; /// Initializes the . public ExecutionDataflowBlockOptions() { } /// Gets the maximum number of messages that may be processed by the block concurrently. public Int32 MaxDegreeOfParallelism { get { return _maxDegreeOfParallelism; } set { Debug.Assert(this != Default, "Default instance is supposed to be immutable."); if (value < 1 && value != Unbounded) throw new ArgumentOutOfRangeException("value"); _maxDegreeOfParallelism = value; } } /// /// Gets whether code using the dataflow block is constrained to one producer at a time. /// /// /// This property defaults to false, such that the block may be used by multiple /// producers concurrently. This property should only be set to true if the code /// using the block can guarantee that it will only ever be used by one producer /// (e.g. a source linked to the block) at a time, meaning that methods like Post, /// Complete, Fault, and OfferMessage will never be called concurrently. Some blocks /// may choose to capitalize on the knowledge that there will only be one producer at a time /// in order to provide better performance. /// public Boolean SingleProducerConstrained { get { return _singleProducerConstrained; } set { Debug.Assert(this != Default, "Default instance is supposed to be immutable."); _singleProducerConstrained = value; } } /// Gets a MaxDegreeOfParallelism value that may be used for comparison purposes. /// The maximum value, usable for comparison purposes. /// Unlike MaxDegreeOfParallelism, this property will always return a positive value. internal Int32 ActualMaxDegreeOfParallelism { get { return (_maxDegreeOfParallelism == Unbounded) ? Int32.MaxValue : _maxDegreeOfParallelism; } } /// Gets whether these dataflow block options allow for parallel execution. internal Boolean SupportsParallelExecution { get { return _maxDegreeOfParallelism == Unbounded || _maxDegreeOfParallelism > 1; } } } /// /// Provides options used to configure the processing performed by dataflow blocks that /// group together multiple messages, blocks such as and /// . /// /// /// is mutable and can be configured through its properties. /// When specific configuration options are not set, the following defaults are used: /// /// /// Options /// Default /// /// /// TaskScheduler /// /// /// /// CancellationToken /// /// /// /// MaxMessagesPerTask /// DataflowBlockOptions.Unbounded (-1) /// /// /// BoundedCapacity /// DataflowBlockOptions.Unbounded (-1) /// /// /// NameFormat /// "{0} Id={1}" /// /// /// MaxNumberOfGroups /// GroupingDataflowBlockOptions.Unbounded (-1) /// /// /// Greedy /// true /// /// /// Dataflow block capture the state of the options at their construction. Subsequent changes /// to the provided instance should not affect the behavior /// of a dataflow block. /// [DebuggerDisplay("TaskScheduler = {TaskScheduler}, MaxMessagesPerTask = {MaxMessagesPerTask}, BoundedCapacity = {BoundedCapacity}, Greedy = {Greedy}, MaxNumberOfGroups = {MaxNumberOfGroups}")] public class GroupingDataflowBlockOptions : DataflowBlockOptions { /// A default instance of . /// /// Do not change the values of this instance. It is shared by all of our blocks when no options are provided by the user. /// internal new static readonly GroupingDataflowBlockOptions Default = new GroupingDataflowBlockOptions(); /// Returns this instance if it's the default instance or else a cloned instance. /// An instance of the options that may be cached by the block. internal new GroupingDataflowBlockOptions DefaultOrClone() { return (this == Default) ? this : new GroupingDataflowBlockOptions { TaskScheduler = this.TaskScheduler, CancellationToken = this.CancellationToken, MaxMessagesPerTask = this.MaxMessagesPerTask, BoundedCapacity = this.BoundedCapacity, NameFormat = this.NameFormat, Greedy = this.Greedy, MaxNumberOfGroups = this.MaxNumberOfGroups }; } /// Whether the block should greedily consume offered messages. private Boolean _greedy = true; /// The maximum number of groups that should be generated by the block. private Int64 _maxNumberOfGroups = Unbounded; /// Initializes the . public GroupingDataflowBlockOptions() { } /// Gets or sets the Boolean value to use to determine whether to greedily consume offered messages. public Boolean Greedy { get { return _greedy; } set { Debug.Assert(this != Default, "Default instance is supposed to be immutable."); _greedy = value; } } /// Gets or sets the maximum number of groups that should be generated by the block. public Int64 MaxNumberOfGroups { get { return _maxNumberOfGroups; } set { Debug.Assert(this != Default, "Default instance is supposed to be immutable."); if (value <= 0 && value != Unbounded) throw new ArgumentOutOfRangeException("value"); _maxNumberOfGroups = value; } } /// Gets a MaxNumberOfGroups value that may be used for comparison purposes. /// The maximum value, usable for comparison purposes. /// Unlike MaxNumberOfGroups, this property will always return a positive value. internal Int64 ActualMaxNumberOfGroups { get { return (_maxNumberOfGroups == Unbounded) ? Int64.MaxValue : _maxNumberOfGroups; } } } }