自定义线程池
场景说明:
今天在工作时遇到一种业务场景,用户上传文件,因为文件比较大所以文件需要异步处理。考虑到服务器性能问题所以通过线程池的方式进行处理
代码部分:
using MassTransit.Util;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace ConsoleApp2
{
internal class Program
{
static void Main(string[] args)
{
for (var i = 0; i < 10; i++) {
var x = Console.ReadLine();
Task task = new Task((object x) => {
Thread.Sleep(10000);
Console.WriteLine($"线程id:{Thread.CurrentThread.ManagedThreadId.ToString()}");
Console.WriteLine($"输入数值:{(string)x}");
},x);
task.Start(SkTaskHelp.Lcts);
}
Console.ReadLine();
}
//内存地址查询
public static string getMemory(object obj)
{
GCHandle handle = GCHandle.Alloc(obj, GCHandleType.WeakTrackResurrection);
IntPtr addr = GCHandle.ToIntPtr(handle);
return $"0x{addr.ToString("X")}";
}
}
public static class SkTaskHelp
{
private static LimitedConcurrencyLevelTaskScheduler _lcts;
public static LimitedConcurrencyLevelTaskScheduler Lcts
{
get
{
if (_lcts == null) {
_lcts = new LimitedConcurrencyLevelTaskScheduler(5);
}
return _lcts;
}
}
}
/// <summary>
/// 提供一个任务调度程序,确保在ThreadPool之上运行时具有最大并发级别。
/// </summary>
public class LimitedConcurrencyLevelTaskScheduler : TaskScheduler
{
/// <summary>Whether the current thread is processing work items.</summary>
[ThreadStatic]
private static bool _currentThreadIsProcessingItems;
/// <summary>The list of tasks to be executed.</summary>
private readonly LinkedList<Task> _tasks = new LinkedList<Task>(); // protected by lock(_tasks)
/// <summary>The maximum concurrency level allowed by this scheduler.</summary>
private readonly int _maxDegreeOfParallelism;
/// <summary>Whether the scheduler is currently processing work items.</summary>
private int _delegatesQueuedOrRunning = 0; // protected by lock(_tasks)
/// <summary>
/// Initializes an instance of the LimitedConcurrencyLevelTaskScheduler class with the
/// specified degree of parallelism.
/// </summary>
/// <param name="maxDegreeOfParallelism">The maximum degree of parallelism provided by this scheduler.</param>
public LimitedConcurrencyLevelTaskScheduler(int maxDegreeOfParallelism)
{
if (maxDegreeOfParallelism < 1) throw new ArgumentOutOfRangeException("maxDegreeOfParallelism");
_maxDegreeOfParallelism = maxDegreeOfParallelism;
}
/// <summary>Queues a task to the scheduler.</summary>
/// <param name="task">The task to be queued.</param>
protected sealed override void QueueTask(Task task)
{
// Add the task to the list of tasks to be processed. If there aren't enough
// delegates currently queued or running to process tasks, schedule another.
lock (_tasks)
{
_tasks.AddLast(task);
if (_delegatesQueuedOrRunning < _maxDegreeOfParallelism)
{
++_delegatesQueuedOrRunning;
NotifyThreadPoolOfPendingWork();
}
}
}
/// <summary>
/// Informs the ThreadPool that there's work to be executed for this scheduler.
/// </summary>
private void NotifyThreadPoolOfPendingWork()
{
ThreadPool.UnsafeQueueUserWorkItem(_ =>
{
// Note that the current thread is now processing work items.
// This is necessary to enable inlining of tasks into this thread.
_currentThreadIsProcessingItems = true;
try
{
// Process all available items in the queue.
while (true)
{
Task item;
lock (_tasks)
{
// When there are no more items to be processed,
// note that we're done processing, and get out.
if (_tasks.Count == 0)
{
--_delegatesQueuedOrRunning;
break;
}
// Get the next item from the queue
item = _tasks.First.Value;
_tasks.RemoveFirst();
}
// Execute the task we pulled out of the queue
base.TryExecuteTask(item);
}
}
// We're done processing items on the current thread
finally { _currentThreadIsProcessingItems = false; }
}, null);
}
/// <summary>Attempts to execute the specified task on the current thread.</summary>
/// <param name="task">The task to be executed.</param>
/// <param name="taskWasPreviouslyQueued"></param>
/// <returns>Whether the task could be executed on the current thread.</returns>
protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
// If this thread isn't already processing a task, we don't support inlining
if (!_currentThreadIsProcessingItems) return false;
// If the task was previously queued, remove it from the queue
if (taskWasPreviouslyQueued) TryDequeue(task);
// Try to run the task.
return base.TryExecuteTask(task);
}
/// <summary>Attempts to remove a previously scheduled task from the scheduler.</summary>
/// <param name="task">The task to be removed.</param>
/// <returns>Whether the task could be found and removed.</returns>
protected sealed override bool TryDequeue(Task task)
{
lock (_tasks) return _tasks.Remove(task);
}
/// <summary>Gets the maximum concurrency level supported by this scheduler.</summary>
public sealed override int MaximumConcurrencyLevel { get { return _maxDegreeOfParallelism; } }
/// <summary>Gets an enumerable of the tasks currently scheduled on this scheduler.</summary>
/// <returns>An enumerable of the tasks currently scheduled.</returns>
protected sealed override IEnumerable<Task> GetScheduledTasks()
{
bool lockTaken = false;
try
{
Monitor.TryEnter(_tasks, ref lockTaken);
if (lockTaken) return _tasks.ToArray();
else throw new NotSupportedException();
}
finally
{
if (lockTaken) Monitor.Exit(_tasks);
}
}
}
}
代码重点部分说明
-
SkTaskHelp:此类用于生成一个单例的自定义调度LimitedConcurrencyLevelTaskScheduler 保证使用的线程调度为同一个调度系统
-
LimitedConcurrencyLevelTaskScheduler 为线程调度自动继承自TaskScheduler
-
Task task = new Task((object x) => { Thread.Sleep(10000); Console.WriteLine($"线程id:{Thread.CurrentThread.ManagedThreadId.ToString()}"); Console.WriteLine($"输入数值:{(string)x}"); },x);
创建一个Task -
task.Start(SkTaskHelp.Lcts); 使用调度自定义调度器运行Task
这样只要设置好调度器线程池的大小 使用该调度器的线程就可以在设置的线程内进行运行,在上一个执行完成之后才会执行下一个线程