113 lines
4.0 KiB
C#
113 lines
4.0 KiB
C#
namespace AyCode.Core.Helpers
|
|
{
|
|
public static class TaskHelper
|
|
{
|
|
public static bool WaitTo(Func<bool> predicate, int msTimeout = 10000, int msDelay = 5, int msFirstDelay = 0)
|
|
=> WaitToAsync(predicate, msTimeout, msDelay, msFirstDelay).GetAwaiter().GetResult();
|
|
|
|
public static bool WaitTo(Func<bool> predicate, int msTimeout, int msDelay, int msFirstDelay, CancellationToken cancellationToken)
|
|
=> WaitToAsync(predicate, msTimeout, msDelay, msFirstDelay, cancellationToken).GetAwaiter().GetResult();
|
|
|
|
public static Task<bool> WaitToAsync(Func<bool> predicate, int msTimeout = 10000, int msDelay = 5, int msFirstDelay = 0)
|
|
=> WaitToAsync(predicate, msTimeout, msDelay, msFirstDelay, CancellationToken.None);
|
|
|
|
public static async Task<bool> WaitToAsync(Func<bool> predicate, int msTimeout, int msDelay, int msFirstDelay, CancellationToken cancellationToken)
|
|
{
|
|
// Use Environment.TickCount64 instead of DateTime.UtcNow.Ticks for better performance
|
|
var endTick = Environment.TickCount64 + msTimeout;
|
|
|
|
if (msFirstDelay > 0)
|
|
await Task.Delay(msFirstDelay, cancellationToken).ConfigureAwait(false);
|
|
|
|
// Check immediately first
|
|
if (predicate())
|
|
return true;
|
|
|
|
// Use PeriodicTimer for efficient polling (.NET 6+)
|
|
using var timer = new PeriodicTimer(TimeSpan.FromMilliseconds(msDelay));
|
|
|
|
while (Environment.TickCount64 < endTick)
|
|
{
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
|
|
if (predicate())
|
|
return true;
|
|
|
|
try
|
|
{
|
|
if (!await timer.WaitForNextTickAsync(cancellationToken).ConfigureAwait(false))
|
|
break;
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Final check
|
|
return predicate();
|
|
}
|
|
|
|
public static void Forget(this Task task)
|
|
{
|
|
if (!task.IsCompleted || task.IsFaulted)
|
|
_ = ForgetAwaited(task);
|
|
|
|
static async Task ForgetAwaited(Task task)
|
|
{
|
|
try
|
|
{
|
|
await task.ConfigureAwait(false);
|
|
}
|
|
catch
|
|
{
|
|
// Swallow exception - fire and forget semantics
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void Forget(this ValueTask task)
|
|
{
|
|
if (!task.IsCompleted || task.IsFaulted)
|
|
_ = ForgetAwaited(task);
|
|
|
|
static async Task ForgetAwaited(ValueTask task)
|
|
{
|
|
try
|
|
{
|
|
await task.ConfigureAwait(false);
|
|
}
|
|
catch
|
|
{
|
|
// Swallow exception - fire and forget semantics
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void Forget<T>(this ValueTask<T> task)
|
|
{
|
|
if (!task.IsCompleted || task.IsFaulted)
|
|
_ = ForgetAwaited(task);
|
|
|
|
static async Task ForgetAwaited(ValueTask<T> task)
|
|
{
|
|
try
|
|
{
|
|
await task.ConfigureAwait(false);
|
|
}
|
|
catch
|
|
{
|
|
// Swallow exception - fire and forget semantics
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void RunOnThreadPool(this Action action) => ToThreadPoolTask(action).Forget();
|
|
public static void RunOnThreadPool<T>(this Func<T> func) => ToThreadPoolTask(func).Forget();
|
|
|
|
public static Task ToThreadPoolTask(this Action action) => Task.Run(action);
|
|
public static Task<T> ToThreadPoolTask<T>(this Func<Task<T>> func) => Task.Run(func);
|
|
public static Task<T> ToThreadPoolTask<T>(this Func<T> func) => Task.Run(func);
|
|
}
|
|
}
|