CI / Go Backend (push) Canceled after 0s
初始化 monorepo: Go后端(7微服务) + Unity客户端(9模块) + 启动器 HTML5原型: Three.js 3D体素世界, Perlin噪声地形, 原版材质, 22种方块 Minecraft创造模式背包: 双栏布局, 拖拽移动物品, 方向性元件引脚 AI助搭策划文档 + 客户端/服务端骨架 + Docker Compose + CI
109 lines
2.8 KiB
C#
109 lines
2.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace PCL.Core.Utils.Threading;
|
|
|
|
// Partly generated by o4-mini-high (20250709)
|
|
|
|
/// <summary>
|
|
/// 允许限制最大并发度的 TaskScheduler
|
|
/// </summary>
|
|
public sealed class LimitedConcurrencyLevelTaskScheduler : TaskScheduler
|
|
{
|
|
[ThreadStatic]
|
|
private static bool _currentThreadIsProcessingItems;
|
|
|
|
private readonly LinkedList<Task> _tasks = [];
|
|
private int _delegatesQueuedOrRunning = 0;
|
|
private readonly int _maxDegreeOfParallelism;
|
|
|
|
public LimitedConcurrencyLevelTaskScheduler(int maxDegreeOfParallelism)
|
|
{
|
|
if (maxDegreeOfParallelism < 1)
|
|
throw new ArgumentOutOfRangeException(nameof(maxDegreeOfParallelism));
|
|
_maxDegreeOfParallelism = maxDegreeOfParallelism;
|
|
}
|
|
|
|
public override int MaximumConcurrencyLevel => _maxDegreeOfParallelism;
|
|
|
|
protected override IEnumerable<Task> GetScheduledTasks()
|
|
{
|
|
var lockTaken = false;
|
|
try
|
|
{
|
|
Monitor.TryEnter(_tasks, ref lockTaken);
|
|
if (lockTaken) return _tasks.ToArray();
|
|
else throw new NotSupportedException();
|
|
}
|
|
finally
|
|
{
|
|
if (lockTaken) Monitor.Exit(_tasks);
|
|
}
|
|
}
|
|
|
|
protected override void QueueTask(Task task)
|
|
{
|
|
lock (_tasks)
|
|
{
|
|
_tasks.AddLast(task);
|
|
if (_delegatesQueuedOrRunning < _maxDegreeOfParallelism)
|
|
{
|
|
_delegatesQueuedOrRunning++;
|
|
ThreadPool.UnsafeQueueUserWorkItem(_ => _ProcessTasks(), null);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void _ProcessTasks()
|
|
{
|
|
_currentThreadIsProcessingItems = true;
|
|
try
|
|
{
|
|
while (true)
|
|
{
|
|
Task item;
|
|
lock (_tasks)
|
|
{
|
|
if (_tasks.Count == 0)
|
|
{
|
|
_delegatesQueuedOrRunning--;
|
|
break;
|
|
}
|
|
item = _tasks.First!.Value;
|
|
_tasks.RemoveFirst();
|
|
}
|
|
TryExecuteTask(item);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
_currentThreadIsProcessingItems = false;
|
|
}
|
|
}
|
|
|
|
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
|
|
{
|
|
if (!_currentThreadIsProcessingItems) return false;
|
|
|
|
if (taskWasPreviouslyQueued)
|
|
{
|
|
return TryDequeue(task) && TryExecuteTask(task);
|
|
}
|
|
else
|
|
{
|
|
return TryExecuteTask(task);
|
|
}
|
|
}
|
|
|
|
protected override bool TryDequeue(Task task)
|
|
{
|
|
lock (_tasks)
|
|
{
|
|
return _tasks.Remove(task);
|
|
}
|
|
}
|
|
}
|