combine projects into one
This commit is contained in:
148
Gallery.Share/Util/ParallelTask.cs
Normal file
148
Gallery.Share/Util/ParallelTask.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Gallery.Util
|
||||
{
|
||||
public class ParallelTask : IDisposable
|
||||
{
|
||||
public static ParallelTask Start(string tag, int from, int toExclusive, int maxCount, Predicate<int> action, int tagIndex = -1, WaitCallback complete = null)
|
||||
{
|
||||
if (toExclusive <= from)
|
||||
{
|
||||
if (complete != null)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(complete);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
var task = new ParallelTask(tag, from, toExclusive, maxCount, action, tagIndex, complete);
|
||||
task.Start();
|
||||
return task;
|
||||
}
|
||||
|
||||
private readonly object sync = new();
|
||||
private int count;
|
||||
private bool disposed;
|
||||
|
||||
public int TagIndex { get; private set; }
|
||||
private readonly string tag;
|
||||
private readonly int max;
|
||||
private readonly int from;
|
||||
private readonly int to;
|
||||
private readonly Predicate<int> action;
|
||||
private readonly WaitCallback complete;
|
||||
|
||||
private ParallelTask(string tag, int from, int to, int maxCount, Predicate<int> action, int tagIndex, WaitCallback complete)
|
||||
{
|
||||
if (maxCount <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(maxCount));
|
||||
}
|
||||
max = maxCount;
|
||||
if (from >= to)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(from));
|
||||
}
|
||||
TagIndex = tagIndex;
|
||||
this.tag = tag;
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.action = action;
|
||||
this.complete = complete;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(DoStart);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
private void DoStart(object state)
|
||||
{
|
||||
#if DEBUG
|
||||
const long TIMEOUT = 60000L;
|
||||
var sw = new System.Diagnostics.Stopwatch();
|
||||
long lastElapsed = 0;
|
||||
sw.Start();
|
||||
#endif
|
||||
for (int i = from; i < to; i++)
|
||||
{
|
||||
var index = i;
|
||||
while (count >= max)
|
||||
{
|
||||
#if DEBUG
|
||||
var elapsed = sw.ElapsedMilliseconds;
|
||||
if (elapsed - lastElapsed > TIMEOUT)
|
||||
{
|
||||
lastElapsed = elapsed;
|
||||
Log.Print($"WARNING: parallel task ({tag}), {count} tasks in queue, cost too much time ({elapsed:n0}ms)");
|
||||
}
|
||||
#endif
|
||||
if (disposed)
|
||||
{
|
||||
#if DEBUG
|
||||
sw.Stop();
|
||||
Log.Print($"parallel task determinate, disposed ({tag}), cost time ({elapsed:n0}ms)");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
Thread.Sleep(16);
|
||||
}
|
||||
lock (sync)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
ThreadPool.QueueUserWorkItem(o =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!action(index))
|
||||
{
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"parallel.start ({tag})", $"failed to run action, index: {index}, error: {ex}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
lock (sync)
|
||||
{
|
||||
count--;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
while (count > 0)
|
||||
{
|
||||
#if DEBUG
|
||||
var elapsed = sw.ElapsedMilliseconds;
|
||||
if (elapsed - lastElapsed > TIMEOUT)
|
||||
{
|
||||
lastElapsed = elapsed;
|
||||
Log.Print($"WARNING: parallel task ({tag}), {count} ending tasks in queue, cost too much time ({elapsed:n0}ms)");
|
||||
}
|
||||
#endif
|
||||
if (disposed)
|
||||
{
|
||||
#if DEBUG
|
||||
sw.Stop();
|
||||
Log.Print($"parallel task determinate, disposed ({tag}), ending cost time ({elapsed:n0}ms)");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
Thread.Sleep(16);
|
||||
}
|
||||
#if DEBUG
|
||||
sw.Stop();
|
||||
Log.Print($"parallel task done ({tag}), cost time ({sw.ElapsedMilliseconds:n0}ms)");
|
||||
#endif
|
||||
complete?.Invoke(null);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user