如何使用单击处理程序等待

时间:2014-01-23 21:33:08

标签: c# asynchronous async-await

我有一个与串口通信的应用程序。我试图使它在执行一系列读取时不会冻结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返回我不关心的东西吗?这似乎很弱。

我希望我已经足够清楚。

2 个答案:

答案 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