【问题标题】:Is this good code for asynchronous downloads on regular interval?这是定期异步下载的好代码吗?
【发布时间】:2016-12-30 04:02:17
【问题描述】:

我正在使用 Windows 服务定期检查更新。就像一两​​分钟。为此,我使用 .net 4.6.1 和

  1. 系统定时器,&
  2. 任务

下面是我的代码

    /// <summary>
    /// Download updates from server
    /// </summary>
    /// <returns></returns>
    private void DownloadUpdate()
    {
        try
        {
            var package = string.Empty;
            if (_server != null)
            {
                timer.Stop();
                package = _server.Download();
                if (package.Length > 0)
                    _server.Install(package);
            }
        }

        finally
        {

            timer.Start();

        }

    }

    /// <summary>
    /// To carry out download asynchronous way
    /// </summary>
    private async void DowloadUpdateAsync()
    {
       await Task.Run(()=>DownloadUpdate());
    }

只是想知道,如果它是管理间隔的正确方法。

【问题讨论】:

  • 我不知道你的完整场景,但我想知道为什么你需要它是异步的。如果DownloadUpdate 打算异步运行,我认为它不应该处理计时器(比如停止/启动它),即使您每次运行一个任务也是如此。我想你想定期异步下载许多包,对吧?!
  • 这可能更适合代码审查网站。 codereview.stackexchange.com
  • @Alisson - 它必须定期检查更新,在下载时,计时器需要保持关闭,它一次只会下载一个包。

标签: c# .net visual-studio timer task-parallel-library


【解决方案1】:
  1. 对于async 方法,如果您不希望它返回结果,请返回Task。见this link。

  2. Task.Run(()=&gt;DownloadUpdate());可以简化为Task.Run(DownloadUpdate);

  3. 我真的看不出有什么理由需要将任务包装在 async 方法中。由于DownloadUpdate 不是异步的,它无论如何都会阻塞一个线程,你需要做的就是将它作为Task 运行或者直接将它排队到线程池中。

【讨论】:

  • Task.Run(()=>Method()) 在这里不等于 Task.Run(Method),因为 Run 无法识别调用方法是 Func 还是 Action。需要对 Action 进行类型转换。
【解决方案2】:

补充 Lifu 的回答:

我建议,您应该在 ContinueWith() 中启动计时器。

TPL 使用垃圾收集器的终结机制来发现失败的任务何时被放弃,导致异常未观察到。发生这种情况时,TaskScheduler 类会引发其 UnobservedTaskException 事件。最好处理您的异常。这是使用 ContinueWith 时的优势。

试试这样的:

    Timer timer = new Timer();
    public Program()
    {
        timer.Interval = 5000;
        timer.Elapsed += DownloadUpdate;
        timer.Enabled = true;
    }

    private void DownloadUpdate(object sender, ElapsedEventArgs e)
    {
        Task.Factory.StartNew((Action)DownloadUpdate).ContinueWith(t =>
        {
            bool shouldTimerStartAgain = true;
            if (t.IsFaulted)
            {
                // handle t.Exception
                // Compute if this task need to stop?
                // If so set shouldTimerStartAgain = false
            }
            if (shouldTimerStartAgain)
            {
                timer.Start();
            }
        });
    }

    private void DownloadUpdate()
    {
        var package = string.Empty;
        if (_server != null)
        {
            timer.Stop();
            package = _server.Download();
            if (package.Length > 0)
                _server.Install(package);
        }
    }

【讨论】:

  • 如果您想处理异常,请使用try/catch。您不应该像这样使用StartNew,也不应该像这样使用ContinueWith 而不是async 方法。
  • @Servy 你能详细说明一下吗?
猜你喜欢
  • 2018-12-29
  • 2021-07-17
  • 2013-07-16
  • 2017-07-24
  • 2017-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-03
相关资源
最近更新 更多