โค้ด
[Spoil] คลิกเพื่อดูข้อความที่ซ่อนไว้using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace TORServices.Systems
{
public static class LimitedTaskSchedulerHelper
{
/// <summary>
/// รัน task ตาม action list โดยจำกัดจำนวนพร้อมกันด้วย Custom TaskScheduler
/// </summary>
///
/*
// ตัวอย่างการใช้งาน RunLimitedTaskScheduler
// สมมติเรามีฟังก์ชัน async ที่ต้องการรันหลายงานพร้อมกัน
static async Task TestTask(int i)
{
await Task.Delay(1000); // จำลองงานที่ใช้เวลา
Console.WriteLine($"Task {i} complete at {DateTime.Now:T}");
}
// ใน method async ใด ๆ
public static async Task ExampleUsage()
{
// สร้างรายการงาน
List<Func<Task>> actions = new List<Func<Task>>
);
for (int i = 1; i <= 10; i++)
{
int taskNum = i; // เก็บค่า i แยกกันเพื่อป้องกัน closure issues
actions.Add(async () => await TestTask(taskNum));
}
// เรียก RunLimitedTaskScheduler
// ตัวอย่างนี้จะรันทีละ 3 งานพร้อมกัน
await LimitedTaskSchedulerHelper.RunLimitedTaskScheduler(actions, 3);
Console.WriteLine("All tasks completed.");
}
*/
public static async Task RunLimitedTaskScheduler(IEnumerable<Func<Task>> actions, int maxConcurrency)
{
if (actions == null) throw new ArgumentNullException(nameof(actions));
if (maxConcurrency < 1) throw new ArgumentOutOfRangeException(nameof(maxConcurrency));
var scheduler = new LimitedConcurrencyLevelTaskScheduler(maxConcurrency);
var factory = new TaskFactory(scheduler);
var tasks = actions.Select(action =>
factory.StartNew(async () => await action()).Unwrap()
).ToList();
await Task.WhenAll(tasks);
}
/// <summary>
/// รัน task ตาม action list โดยจำกัดจำนวนพร้อมกันด้วย SemaphoreSlim
/// </summary>
/*
// ตัวอย่างฟังก์ชัน async ที่เราต้องการรันหลายงาน
static async Task TestTask(int i)
{
await Task.Delay(1000); // จำลองงานที่ใช้เวลา
Console.WriteLine($"Task {i} complete at {DateTime.Now:T}");
}
// ตัวอย่างการใช้งาน RunLimitedWithSemaphoreSlim
public static async Task ExampleUsage()
{
// สร้างรายการงาน
List<Func<Task>> actions = new List<Func<Task>>
);
for (int i = 1; i <= 10; i++)
{
int taskNum = i; // ป้องกัน closure issue
actions.Add(async () => await TestTask(taskNum));
}
// เรียก RunLimitedWithSemaphoreSlim
// ตัวอย่างนี้จะรันทีละ 3 งานพร้อมกัน
await LimitedTaskSchedulerHelper.RunLimitedWithSemaphoreSlim(actions, 3);
Console.WriteLine("All tasks completed.");
}
*/
public static async Task RunLimitedWithSemaphoreSlim(IEnumerable<Func<Task>> actions, int maxConcurrency)
{
if (actions == null) throw new ArgumentNullException(nameof(actions));
if (maxConcurrency < 1) throw new ArgumentOutOfRangeException(nameof(maxConcurrency));
var semaphore = new SemaphoreSlim(maxConcurrency);
var tasks = actions.Select(async action =>
{
await semaphore.WaitAsync();
try
{
await action();
}
finally
{
semaphore.Release();
}
}).ToList();
await Task.WhenAll(tasks);
}
}
/// <summary>
/// Custom TaskScheduler จำกัดจำนวนงานที่รันพร้อมกัน
/// </summary>
public class LimitedConcurrencyLevelTaskScheduler : TaskScheduler
{
[ThreadStatic] private static bool _currentThreadIsProcessingItems;
private readonly LinkedList<Task> _tasks = new LinkedList<Task>
);
private readonly int _maxDegreeOfParallelism;
private int _delegatesQueuedOrRunning = 0;
public LimitedConcurrencyLevelTaskScheduler(int maxDegreeOfParallelism)
{
if (maxDegreeOfParallelism < 1)
throw new ArgumentOutOfRangeException(nameof(maxDegreeOfParallelism));
_maxDegreeOfParallelism = maxDegreeOfParallelism;
}
protected override void QueueTask(Task task)
{
lock (_tasks)
{
_tasks.AddLast(task);
if (_delegatesQueuedOrRunning < _maxDegreeOfParallelism)
{
_delegatesQueuedOrRunning++;
ThreadPool.UnsafeQueueUserWorkItem(_ =>
{
_currentThreadIsProcessingItems = true;
try
{
while (true)
{
Task item;
lock (_tasks)
{
if (_tasks.Count == 0)
{
_delegatesQueuedOrRunning--;
break;
}
item = _tasks.First.Value;
_tasks.RemoveFirst();
}
base.TryExecuteTask(item);
}
}
finally
{
_currentThreadIsProcessingItems = false;
}
}, null);
}
}
}
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
if (!_currentThreadIsProcessingItems) return false;
if (taskWasPreviouslyQueued && !TryDequeue(task)) return false;
return base.TryExecuteTask(task);
}
protected override bool TryDequeue(Task task)
{
lock (_tasks) return _tasks.Remove(task);
}
public override int MaximumConcurrencyLevel => _maxDegreeOfParallelism;
protected 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);
}
}
}
}
ช่วงนี้เขียนโค้ดทำกงานกับไฟล์ เยอะมากเลย ครับ
และส่วนที่ผมใช้ทำกงานด้วย มี 2 ตัว คือ SemaphoreSlim และ TaskScheduler
อยากทราบว่าปกติแล้วท่านที่เขียนโปรแกรมเป็นประจำใช้ตัวไหนมากกว่ากัน หรือ ใช้ตัวอื่น ครับ
C# SemaphoreSlim vs TaskScheduler ใช้อะไรดี ครับ
[Spoil] คลิกเพื่อดูข้อความที่ซ่อนไว้
ช่วงนี้เขียนโค้ดทำกงานกับไฟล์ เยอะมากเลย ครับ
และส่วนที่ผมใช้ทำกงานด้วย มี 2 ตัว คือ SemaphoreSlim และ TaskScheduler
อยากทราบว่าปกติแล้วท่านที่เขียนโปรแกรมเป็นประจำใช้ตัวไหนมากกว่ากัน หรือ ใช้ตัวอื่น ครับ