【发布时间】:2019-10-29 21:40:12
【问题描述】:
我有一个问题,我有一个普通函数,它调用一个异步函数,它在循环中调用另一个异步函数。问题是,有对我的硬件接口的调用(例如执行电机运动的扫描),并且由于某种原因,这似乎会持续阻塞 UI 线程,直到我们真正完成整个“开始”函数的执行。
我不确定我做错了什么,但我觉得某些部分可能不应该在 UI 线程上完成,也许应该在另一个线程上完成......我不完全确定如何做到这一点。下面是代码示例。每次扫描时,UI 都会更新,每次扫描都会突出显示“按钮”。
public void StartProcess(ObservableCollection<ObjModel> objs)
{
// Cancel
if (cancellationTokenSource != null)
{
// Cancel tasks
cancellationTokenSource.Cancel();
cancellationTokenSource.Dispose();
return;
}
cancellationTokenSource = new CancellationTokenSource();
if (MachineController.Instance.InitHardware())
{
StartScan(objs);
}
else
{
Clean();
}
}
private async void StartScan(ObservableCollection<ObjModel> objs)
{
// We are now running
InfoModel.IsRunning = true;
for (int index = 1; index < Size; index++)
{
MachineController.Instance.MoveToIndex(index - 1);
if ((index - 1) % 2 == 0)
{
for (int iAIndex = 1; iAIndex < Size; iAIndex++)
{
var obj = objs.Where(x => x.R == index && x.C == iAIndex).FirstOrDefault();
await DoScan(obj);
}
}
}
Clean();
}
private async Task DoScan(ObjModel obj)
{
MachineController.Instance.MoveToCIndex(obj.C - 1);
// Set the task to only take a couple of seconds
bool check = MachineController.Instance.Scan();
if (check)
{
await Task.Delay(5, cancellationTokenSource.Token);
// Plot
UpdateGraph(obj.R, obj.C);
}
}
【问题讨论】:
-
不要使用
async void方法,事件处理程序除外。除此之外,MachineController.Instance.Scan()显然在 UI 线程中被调用并阻塞了它。你也许可以把它包裹在await Task.Run(() => MachineController.Instance.Scan()); -
嗨克莱门斯。谢谢。那我应该从 StartScan 函数中删除异步吗? DoScan 还能等待吗?...
-
不,它应该声明为
private async Task StartScan(...),并在调用时等待。就像DoScan。这同样适用于StartProcess。 -
StartScan(objs);->await StartScan(objs); -
唯一不会在调用线程上运行的代码是
Task.Delay()(实际上我相信它会使用计时器)。事实上,您await是only为什么您的代码是异步的但没有达到您期望的水平的原因。其余的在调用线程上运行,这当然是 UI 线程,因此是阻塞的。你忘记使用异步 I/O 了吗?Task.Run()?
标签: c# wpf multithreading async-await