For an exposure.#7
Conversation
Copoilot: "Update project structure and enhance async capabilities Updated solution and project files to SDK-style format targeting .NET 9.0. Added new project `ParallelExtensionsExtrasCore` and introduced numerous files with classes and extension methods to improve asynchronous programming, including support for parallel LINQ, asynchronous I/O operations, and enhanced task scheduling features. Modernized the codebase for better usability and performance in multi-threaded environments."
There was a problem hiding this comment.
Pull request overview
This PR adds a comprehensive set of parallel extension utilities to the codebase under the title "For an exposure." The changes introduce multiple task schedulers, parallel algorithms, partitioners, and extension methods for asynchronous programming.
Key Changes:
- Added 11 custom task schedulers for various execution patterns (work-stealing, round-robin, prioritization, etc.)
- Implemented parallel algorithm utilities including map-reduce, sorting, scanning, and filtering
- Added partitioners for chunked and single-item processing
- Created extensive extension methods for Task, TaskFactory, and LINQ integration
Reviewed changes
Copilot reviewed 83 out of 84 changed files in this pull request and generated 64 comments.
Show a summary per file
| File | Description |
|---|---|
| SortedTopN.cs | Utility class for maintaining top-N sorted elements |
| WorkStealingTaskScheduler.cs | Task scheduler implementing work-stealing pattern |
| ThreadPerTaskkScheduler.cs | File naming issue: Extra 'k' in filename |
| Other schedulers (11 files) | Various specialized task schedulers for different patterns |
| Partitioners (2 files) | Chunk and single-item partitioning implementations |
| ParallelAlgorithms (10 files) | Map, reduce, sort, scan, and other parallel algorithms |
| Extensions (20+ files) | Extension methods for Task, LINQ, and EAP patterns |
| ParallelExtensionsExtrasCore.csproj | Project configuration targeting .NET 9.0 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // to the resulting task when we're done. | ||
| var tasks = new List<Task>(); | ||
|
|
||
| // Run seqeuentially through all of the provided functions. |
There was a problem hiding this comment.
Typo in comment: 'seqeuentially' should be 'sequentially'.
| /// <summary>An invalid I/O completion port handle value.</summary> | ||
| private IntPtr INVALID_IOCP_HANDLE = IntPtr.Zero; | ||
|
|
||
| /// <summary>The I/O completion porth handle.</summary> |
There was a problem hiding this comment.
Typo in comment: 'porth' should be 'port'.
| (accum) => accum.Values); | ||
| } | ||
|
|
||
| /// <summary>A comparer that comparers using the inverse of the default comparer.</summary> |
There was a problem hiding this comment.
Typo in comment: 'comparers' should be 'compares'.
| //-------------------------------------------------------------------------- | ||
| // | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // | ||
| // File: ThreadPerTaskScheduler.cs | ||
| // | ||
| //-------------------------------------------------------------------------- | ||
|
|
||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
|
|
||
| namespace System.Threading.Tasks.Schedulers | ||
| { | ||
| /// <summary>Provides a task scheduler that dedicates a thread per task.</summary> | ||
| public class ThreadPerTaskScheduler : TaskScheduler | ||
| { | ||
| /// <summary>Gets the tasks currently scheduled to this scheduler.</summary> | ||
| /// <remarks>This will always return an empty enumerable, as tasks are launched as soon as they're queued.</remarks> | ||
| protected override IEnumerable<Task> GetScheduledTasks() { return Enumerable.Empty<Task>(); } | ||
|
|
||
| /// <summary>Starts a new thread to process the provided task.</summary> | ||
| /// <param name="task">The task to be executed.</param> | ||
| protected override void QueueTask(Task task) | ||
| { | ||
| new Thread(() => TryExecuteTask(task)) { IsBackground = true }.Start(); | ||
| } | ||
|
|
||
| /// <summary>Runs the provided task on the current thread.</summary> | ||
| /// <param name="task">The task to be executed.</param> | ||
| /// <param name="taskWasPreviouslyQueued">Ignored.</param> | ||
| /// <returns>Whether the task could be executed on the current thread.</returns> | ||
| protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) | ||
| { | ||
| return TryExecuteTask(task); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
The filename contains a typo: 'ThreadPerTaskkScheduler.cs' should be 'ThreadPerTaskScheduler.cs' (extra 'k'). The file header comment on line 5 shows the correct name 'ThreadPerTaskScheduler.cs', indicating this is a file naming issue.
| public static partial class TaskFactoryExtensions | ||
| { | ||
| /// <summary> | ||
| /// Creates a continuation Task that will compplete upon |
There was a problem hiding this comment.
Typo in comment: 'compplete' should be 'complete'.
| /// <summary>Whether this queue has been disposed.</summary> | ||
| internal bool _disposed; | ||
| /// <summary>Gets the priority for this queue.</summary> | ||
| internal int _priority; |
There was a problem hiding this comment.
Field '_priority' can be 'readonly'.
| /// </summary> | ||
| private readonly int _concurrencyLevel; | ||
| /// <summary>Whether we're processing tasks on the current thread.</summary> | ||
| private static ThreadLocal<bool> _taskProcessingThread = new ThreadLocal<bool>(); |
There was a problem hiding this comment.
Field '_taskProcessingThread' can be 'readonly'.
| private readonly int m_concurrencyLevel; | ||
| private readonly Queue<Task> m_queue = new Queue<Task>(); | ||
| private WorkStealingQueue<Task>[] m_wsQueues = new WorkStealingQueue<Task>[Environment.ProcessorCount]; | ||
| private Lazy<Thread[]> m_threads; |
There was a problem hiding this comment.
Field 'm_threads' can be 'readonly'.
| private volatile int m_headIndex = 0; | ||
| private volatile int m_tailIndex = 0; | ||
|
|
||
| private object m_foreignLock = new object(); |
There was a problem hiding this comment.
Field 'm_foreignLock' can be 'readonly'.
| if (_targetScheduler == null) | ||
| { | ||
| // Get all of the tasks, filtering out nulls, which are just placeholders | ||
| // for tasks in other sub-schedulers | ||
| return _blockingTaskQueue.Where(t => t != null).ToList(); | ||
| } | ||
| // otherwise get them from the non-blocking queue... | ||
| else | ||
| { | ||
| return _nonthreadsafeTaskQueue.Where(t => t != null).ToList(); | ||
| } |
There was a problem hiding this comment.
Both branches of this 'if' statement return - consider using '?' to express intent better.
.NetFramework 4.0 lacks support.