【发布时间】:2017-06-30 22:43:16
【问题描述】:
环境
- Windows 7
- Visual Studio
- C#
我想要做什么
我正在尝试构建一个应用来评估公司产品。为了安全起见,下面的描述有所抽象。
这个应用程序所做的是改变产品中的某个参数,看看产品的某个值是如何变化的。所以我需要做两件事。
- 每隔一段时间更改一次参数
- 以一定的间隔在文本框中显示值
图表是这样的。
这些任务应该一直重复,直到按下取消按钮。
用户界面具有以下控件:
- button1:开始按钮
- button2:取消按钮
- textbox1 : 显示从设备获取的值
这是我写的代码。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
CancellationTokenSource cts = new CancellationTokenSource();
private async void button1_Click(object sender, EventArgs e)
{
await Task1();
await Task2();
}
private async Task Task1()
{
while (!cts.IsCancellationRequested)
{
Thread.Sleep(500);
ChangeParameter(0);
Thread.Sleep(1000);
ChangeParameter(10);
Thread.Sleep(500);
ChangeParameter(0);
}
}
private void ChangeParameter(double param)
{
// change device paremeter
Console.WriteLine("devicep parameter changed : " + param);
}
private async Task Task2()
{
while (!cts.IsCancellationRequested)
{
Thread.Sleep(100);
int data = GetDataFromDevice();
UpdateTextBoxWithData(data);
}
cts.Token.ThrowIfCancellationRequested();
}
private int GetDataFromDevice()
{
//pseudo code
var rnd = new Random();
return rnd.Next(100);
}
private void UpdateTextBoxWithData(int data)
{
textBox1.AppendText(data.ToString() + "\n");
// debug
Console.WriteLine("data : " + data);
}
private void button2_Click(object sender, EventArgs e)
{
cts.Cancel();
}
}
问题
但是,这段代码有两个问题。
- UI 冻结。
- Task2 永远不会执行。
第二个问题源自await,因为它一个一个地执行任务。我本可以使用 Task.Run() 但这不允许向 textBox 添加值,因为它与 UI 线程不同。
我该如何解决这些问题?任何帮助将不胜感激。
【问题讨论】:
-
用
await Task.Delay(500)替换Thread.Sleep(500) -
总是为非 UI 任务启动新线程,否则它们在 UI 线程上运行并从 UI 刷新中夺走处理能力。他们可以在运行完成时使用调用提醒 UI。
-
@Nyerguds 不要为非 UI 任务启动新线程。使用 Tasks、
async/await、PLINQ 或 Dataflow,让框架调度作业 -
@CallumLinington 不,如果您使用
async/await和 IProgress,您不需要需要调用 -
@Nyerguds 您正在混合线程和异步/等待。如果 OP 有任何异步代码,
await将确保执行将在异步代码完成后返回到 UI 线程。如果你使用await,又需要使用Invoke,那你就错了
标签: c# asynchronous