问题描述
我只想说我今天才开始尝试使用 Async,所以我对自己在做什么的理解非常有限.
I'm just going to preface this by saying I just started trying to use Async today, so I have a very limited understanding of what I am doing.
我之前使用线程从串行端口读取数据,将该数据处理为要写入的数据,然后再写入.我有一个线程读取数据并将其放入缓冲区,另一个线程处理来自缓冲区的数据,最后一个线程写入它.这样,如果我点击一个按钮,我可以发送额外的数据.
I was previously using threads to read data from a serial port, process that data into data to write, and then writing it. I had 1 thread reading data and placing it into a buffer, another thread processing data from a buffer, and a final thread writing it. This way if I clicked a button, I could send additional data.
现在我只是想学习并确保我做的一切都正确,所以我尝试从串行端口读取数据,并将该数据添加到多行文本框中.代码如下:
Now I am just trying to learn and ensure I am doing everything properly, so I am trying to read data from the serial port, and add that data to a multilined textbox. Here's the code:
连接串口,如果成功,调用异步的UpdateMessageBox
:
Connect to serial port, if successful, call UpdateMessageBox
which is async:
private void serialConnectClick(object sender, EventArgs e)
{
if (!_serialConnected)
{
_serialConnected = SerialConnect(portCombo.Text, int.Parse(baudCombo.Text));
if (!_serialConnected)
{
portCombo.SelectedIndex = 0;
messageTextBox.Text += "Failed to connect.
";
return;
}
serialConnectBtn.Text = "Disconnect";
serialStatusLabel.Text = "Serial: Connected";
serialStatusLabel.ForeColor = Color.Blue;
messageTextBox.Text += "Connected
";
VDIportCombo.Enabled = false;
soundSuccess.Play();
UpdateMessageBox(); // this is an async function
}
}
这会不断调用 ReadLineAsync
并将结果添加到文本框:
This continuously calls ReadLineAsync
and adds the result to the textbox:
public async Task UpdateMessageBox()
{
messageTextBox.Text += "Reading data from serial.";
while (_serialConnected)
{
string message = await SerialReadLineAsync(serial);
messageTextBox.Text += message;
}
}
这会在 SerialPort.BaseStream
上执行 ReadAsync
,并且仅在我们得到整行时才返回数据(由换行符表示):
And this does ReadAsync
on the SerialPort.BaseStream
, and only returns data when we get a full line (denoted by a newline character):
async Task<string> SerialReadLineAsync(SerialPort serialPort)
{
byte[] buffer = new byte[1];
string result = string.Empty;
Debug.WriteLine("Let's start reading.");
while (true)
{
await serialPort.BaseStream.ReadAsync(buffer, 0, 1);
result += serialPort.Encoding.GetString(buffer);
if (result.EndsWith(serialPort.NewLine))
{
result = result.Substring(0, result.Length - serialPort.NewLine.Length);
result.TrimEnd('
','
');
Debug.Write(string.Format("Data: {0}", result));
result += "
";
return result;
}
}
}
我做的每一件事都正确吗?我可以从 UI 线程调用异步方法吗?Visual Studios 告诉我我应该使用 await,但这只是建议.
Am I doing everything correctly? Can I call an async method from the UI thread? Visual studios is telling me I should use await, but it is just suggesting that.
我希望其他代码在 UI 线程持续读取时运行,因此我不想 await
UpdateMessageBox
函数.如果这是一个线程,我只想让读取线程在后台运行,我只会做 myReadThread.Start()
,异步有类似的东西吗?
I want other code to run on the UI thread while it is continuously reading, so I don't want to await
the UpdateMessageBox
function. If this were a thread, I would just want the read thread to operate in the background, and I would just do myReadThread.Start()
, is there something similar for async?
澄清一下,这段代码确实有效,但我想知道这是否是我正在做的事情的正确"方式.
Just to clarify, this code does work, but I want to know if it's the "proper" way to do what I am doing.
推荐答案
你需要改变:
private void serialConnectClick(object sender, EventArgs e)
到
private async void serialConnectClick(object sender, EventArgs e)
...并将对 UpdateMessageBox();
的调用更改为:
...and change the call to UpdateMessageBox();
to:
await UpdateMessageBox().ConfigureAwait(true);
UpdateMessageBox
应使用 ConfigureAwait(true)
以捕获当前上下文 (UI),否则 messageTextBox.Text += message;
将在不同的线程上执行:
UpdateMessageBox
should use ConfigureAwait(true)
in order to capture the current context (UI) else the messageTextBox.Text += message;
would execute on a different thread:
public async Task UpdateMessageBox()
{
messageTextBox.Text += "Reading data from serial.";
while (_serialConnected)
{
string message = await SerialReadLineAsync(serial).ConfigureAwait(true);
messageTextBox.Text += message;
}
}
在SerialReadLineAsync
中,你可以改变:
await serialPort.BaseStream.ReadAsync(buffer, 0, 1);
...到:
await serialPort.BaseStream.ReadAsync(buffer, 0, 1).ConfigureAwait(false);
...因为 SerialReadLineAsync
语句与 UI 无关.
...because SerialReadLineAsync
statements are not related to the UI.
一般提示是"async all the way",这意味着任何 await
是 async
方法的方法也需要进行 async
并依次 await
ed.在调用堆栈中重复此操作.
The general tip is "async all the way" which means any method that await
s an async
method also needs to be made async
and in turn await
ed. Repeat this up the call-stack.
这篇关于正确地从串口异步连续读取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!