AyCode.Core/AyCode.Core/Helpers/TaskHelper.cs

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);
}
}