我有一个与串口通信的应用程序。我试图使它在执行一系列读取时不会冻结UI。我最初使用的是一个线程,但从长远来看,它不会运行良好(代码比下面的代码复杂得多)。我试图找出异步/等待,这是我到目前为止所尝试的。
我有一个点击处理程序和相关的方法(详细信息,包括一些方法的参数,为简单起见而删除),如下所示:
private void cmdOpenModPort_Click(object sender, EventArgs e) {
// stuff
CheckBoardsAsync();
// stuff
}
private async void CheckBoardsAsync() {
// Read from a serial port with different settings.
for (byte iTryAdrs = 125; iTryAdrs <= 144; iTryAdrs++) {
ushort[] registers = await mt.ReadRegistersChkSeeBrdAsync(iTryAdrs);
if (registers != null) {
// Update UI based on registers
} else {
// Update UI
}
}
}
public async Task<ushort[]> ReadRegistersChkSeeBrdAsync(byte b) {
// can't await because the method is not async.
return ReadRegistersChkSeeBrd(b);
}
public ushort[] ReadRegistersChkSeeBrd(byte b) {
try {
// read from serial port. NOT an asynchronous method and it is
// calling a method from a package so I cannot control this.
return master.ReadHoldingRegisters(b);
} catch (Exception) {
return null;
}
}
这不起作用,因为在CheckBoardsAsync完成之前,单击处理程序不会完成。我希望对CheckBoardsAsync的调用是异步的,但是该方法会进行一系列异步调用,并且本身不需要返回任何内容,因此没有值等待。由于它没有返回任何东西,我无法等待它。
那么处理这个问题的正确方法是什么?我的理解是在这种情况下我不应该使用线程,因为我在等待I / O,并且几乎没有任何计算。所以这似乎是正确的方法。我只是伪造它并让CheckBoardsAsync返回我不关心的东西吗?这似乎很弱。
我希望我已经足够清楚。
答案 0 :(得分:3)
您应该收到警告,指出async
方法中没有await
个调用。将方法标记为async
不会自动使其异步,只允许使用await
关键字。这里你有CPU绑定工作,没有IO绑定工作,所以你想要做的是在另一个线程中执行该工作(可以使用Task.Run
完成)然后异步等待那个
更改很简单,只需完全删除ReadRegistersChkSeeBrdAsync
并替换:
ushort[] registers = await mt.ReadRegistersChkSeeBrdAsync(iTryAdrs);
与
ushort[] registers = await Task.Run(() =>
mt.ReadRegistersChkSeeBrd(iTryAdrs));
最好完全删除CheckBoardsAsync
方法并让该方法的主体只是cmdOpenModPort_Click
的主体。 (或者,就此而言,只需将CheckBoardsAsync
作为点击处理程序附加。)
答案 1 :(得分:0)
您需要让它返回Task
(不是Task<T>
)
然后,即使它没有返回值,您也可以await
。