如何使用不同的经过时间安排异步执行?

时间:2015-12-11 12:43:26

标签: c# async-await

我有两组需要单独执行的作业,不能并行运行。作业涉及Web通信,因此使用了异步。

目前,我已System.Windows.Forms.Timer设置为使用Task.Run()执行批处理。为了避免可能的同时执行,首先我想我可以在计时器'lock() {}内简单地使用Tick(我在滴滴涕时用倒计时更新UI)。然后意识到我需要.Wait()才能完成任务,否则它只会退出关键部分。

然后我意识到所有这一切都在UI线程上运行,所以就像那些Elmer Fudd的场景,他将步枪指向一个洞而另一个则是另一个指向他的。

是否有一种简单的钉锤方法可以在保持相互排除执行的同时不阻止UI线程?

以下是其中一个计时器的示例:

_timer = new Timer { Interval = 1000 };
_timer.Tick += (sender, args) =>
{
    var timeSpan = _nextRun - DateTime.Now;
    if (timeSpan.Seconds >= 0)
    {
        UpdateCountdownMessage(string.Format("{0:00}:{1:00}:{2:00} to next run.", timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds));
    }
    else
    {
        lock (_runLock)
        {
            Task.Run(() => RunJobs(_batch1Jobs)).Wait();
        }
    }
};

为了更清楚,有一个第二个计时器,我们称之为_timer2,类似地更新了不同的倒计时,并在它达到0时运行_batch2Jobs

2 个答案:

答案 0 :(得分:2)

首先,您需要摆脱lock并切换到SemaphoreSlim

SemaphoreSlim _runLock = new SemaphoreSlim(1, 1);

然后你可以使用这样的东西

_timer.Tick += async (sender, args) =>
{
    var timeSpan = _nextRun - DateTime.Now;
    if (timeSpan.Seconds >= 0)
    {
        UpdateCountdownMessage(string.Format("{0:00}:{1:00}:{2:00} to next run.", timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds));
    }
    else
    {
        _timer.Enabled = false;
        try
        {
            await Task.Run(async () =>
            {
                await _runLock.WaitAsync();
                try { RunJobs(_batch1Jobs); }
                finally { _runLock.Release(); }
            });
        }
        finally { _timer.Enabled = true; }
    }
};

请注意,永远不要在UI线程上使用lockTask.Wait来执行长时间运行的任务。 UI代码应仅使用async/await构造。

答案 1 :(得分:0)

你应该使用任务:

Task T1 = Task.Factory.StartNew(() => {/*do work */});
Task T2 = T1.ContinueWith((antecedent) => {/*do work 2*/});