如何为延迟任务添加时间?

时间:2017-09-22 08:59:55

标签: c# async-await task filesystemwatcher

我有一个进程,我调高FileSystemWatcher来查看传入文件的文件系统。

我设置Task.Delay的延迟,在设置取消令牌或时间到期后(例如10分钟)取消FSW。

watcher.EnableRaisingEvents = true;

// start the timer
RunAfterDelay(TimeSpan.FromMinutes(10), cts.Token, () =>
{
    // get rid of the watcher
    watcher.Dispose();
});

private async void RunAfterDelay(TimeSpan delay, CancellationToken token, Action action)
{
    await Task.Delay(delay, token);
    if (!token.IsCancellationRequested)
    {
        action();
    }
}

但是我想以一种方式配置它,以便每次出现新文件时都能添加额外的延迟。因此有效地实现了某种滑动到期延迟。

1 个答案:

答案 0 :(得分:2)

您可以稍微更改延迟方法,以便能够改变执行时间。

我为你创建了一个小例子。

然后你可以用一种简单的方式对FileSystemWatcher进行“延迟处理”:

CancellationTokenSource cts = new CancellationTokenSource();
await watcher.DisposeDelayed(TimeSpan.FromSeconds(10), cts.Token);

我为DisposeDelayed创建了一个扩展方法FileSystemWatcher

static class Utilities
{
    public static async Task DisposeDelayed(this FileSystemWatcher watcher, TimeSpan inactivePeriod, CancellationToken ct)
    {
        DateTime disposalTime = DateTime.Now + inactivePeriod;
        FileSystemEventHandler postponeTrigger = (s, e) => disposalTime = DateTime.Now + inactivePeriod;
        watcher.Created += postponeTrigger;
        watcher.Changed += postponeTrigger;
        // add here other event handlers you need to postpone the disposal

        try
        {
            await RunAtTimePoint(() => disposalTime, ct, watcher.Dispose).ConfigureAwait(false);
        }
        finally
        {
            // don't forget to unsubscribe from each event
            watcher.Created -= postponeTrigger;
            watcher.Changed -= postponeTrigger;
        }
    }

    // You can also use this method for other tasks if you need
    public static async Task RunAtTimePoint(Func<DateTime> execTimeProvider, CancellationToken token, Action action)
    {
        int delayTime;
        do
        {
            // first, calculate the time left until the execution
            DateTime execTime = execTimeProvider();
            TimeSpan timeLeft = execTime - DateTime.Now;

            // we delay in 1000 ms chunks;
            // but if the delay time is less, we need to handle that
            delayTime = (int)Math.Min(1000d, timeLeft.TotalMilliseconds);
            if (delayTime > 0)
            {
                // don't forget the ConfigureAwait call:
                // we don't need the context switch each time
                await Task.Delay(delayTime, token).ConfigureAwait(false);
            }
        }
        while (delayTime > 0 && !token.IsCancellationRequested);

        if (!token.IsCancellationRequested)
        {
            action();
        }
    }
}