【问题标题】:How to reset a Task.Delay() after a event fired?事件触发后如何重置 Task.Delay()?
【发布时间】:2016-01-20 11:16:48
【问题描述】:

在我的 FileSystemWatcher 超过 5 分钟没有收到任何更改后,我试图让一些代码触发。

我目前的方法是在更改后调用await Task.Delay();,希望用户届时完成。这显然是不是要走的路。

所以我的问题是:如何在事件触发后重置 Task.Delay()?

【问题讨论】:

  • 一个普通的计时器还没有过时。

标签: c# delay reset filesystemwatcher


【解决方案1】:

您无法“重置”Task.Delay,但您可以重置计时器,使其成为解决此问题的理想选择。

这是一个例子:

    private System.Threading.Timer timer;

    public void Start()
    {
        timer = new System.Threading.Timer(_ => fireMyCode());
        restartTimer();
    }

    private void onFileChanged(object sender, EventArgs e)
    {
        restartTimer();
    }

    private void restartTimer()
    {
        timer.Change(TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
    }

但是你不必使用定时器,你仍然可以使用Task.Delay 和一个额外的任务:想法是等待两个任务,延迟和等待文件更改(你可以使用TaskCompletionSource从事件“创建”任务)。 如果延迟任务首先完成,请触发您的代码。

这是一个例子:

    TaskCompletionSource<object> fileChanged = new TaskCompletionSource<object>();

    private void onFileChanged(object sender, EventArgs e)
    {
        fileChanged.TrySetResult(null);
    }

    private async Task endlessLoop()
    {
        while (true)
        {
            await handleFilesNotChanged();
        }
    }

    private async Task handleFilesNotChanged()
    {
        Task timeout = Task.Delay(TimeSpan.FromMinutes(5));
        Task waitForFile = fileChanged.Task;

        if (await Task.WhenAny(timeout, waitForFile) == timeout)
        {
            fireMyCode();
        }
        fileChanged = new TaskCompletionSource<object>();
    }

【讨论】:

  • 什么叫无限循环?循环它是否安全?即使进行了无限循环检查以查看 fireMyCode 是否已完成,我仍然会遇到以下代码挂起。
  • 什么叫无限循环?取决于您的应用程序的上下文。比如你可以在点击一个按钮的时候调用它(一个Windows Form例子:private async void button1_Click(object sender, EventArgs e) {await greatLoop(); }),循环它安全吗?你的意思是,从循环中调用 neverLoop 函数?如果这就是问题所在,那么不,你不想这样做,它只运行一次,因为它本身运行一个无限循环。
  • 我想我很困惑为什么你必须循环它?如果您不循环,延迟不会继续吗?由于某种原因,此代码挂起我的应用程序。什么开始超时?超时如何完成并因此等于任何已完成的任务?为什么不调用handleFilesNotChanged 为什么要通过循环呢?
  • 在第一行,它开始计算 5 分钟的任务,称为超时。在第二行中,它开始等待名为 waitForFile 的任务中的文件更改。这两个现在并行发生。当我执行 Task.WhenAny 时,该方法将阻塞,直到其中一个任务完成,并返回首先完成的任务。如果超时任务首先完成,这意味着我已经等待了 5 分钟并且没有文件更改,所以我“触发我的代码”。但是,如果文件更改首先完成,一切都很好,但现在我必须再次启动我的计时器,因此循环。如果没有循环,这只会发生一次。
  • 如果您有大量的文件快速连续更改,您将有一个堆 o' 计时器,每个计时器坐 5 分钟。最终,它们都会过期并且什么都不做(因为它们的所有WhenAnys 已经对每个更改的文件感到满意)。如果文件更改得足够快,理论上您可以完全耗尽内存。至少当系统停止运行时,文件不太可能保持如此快速的变化。 :-) 一旦计时器不再有用就释放计时器的实现会更好。文件更改时取消timeout 的一种方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-26
  • 2011-11-28
  • 2014-09-18
相关资源
最近更新 更多