我有两组需要单独执行的作业,不能并行运行。作业涉及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
。
答案 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线程上使用lock
或Task.Wait
来执行长时间运行的任务。 UI代码应仅使用async/await
构造。
答案 1 :(得分:0)
你应该使用任务:
Task T1 = Task.Factory.StartNew(() => {/*do work */});
Task T2 = T1.ContinueWith((antecedent) => {/*do work 2*/});