在 C# 中;从后台线程检查更改的最有效方法是什么?
In C#; what is the most efficent way to check for changes from a background thread?
我为我的每个网络通信创建了一个线程,每当他们收到来自客户端的回复时,他们就会将响应添加到列表中。我正在执行下面的任务以查看是否有任何通信进来。它在屏幕上显示最近的一个。
Task task = new Task(
(() =>
{
int i = 0;
while (true)
{
if (responses.Count > i){
Debug.WriteLine(responses[i]);
int index = Form.ActiveForm.Controls.IndexOfKey("responseBox");
Form.ActiveForm.Invoke((MethodInvoker) (() => Form.ActiveForm.Controls[index].Visible = true));
Form.ActiveForm.Invoke((MethodInvoker) (() => Form.ActiveForm.Controls[index].Text = responses[i]));
i++;
}
}
}));
task.Start();
我的问题是;我有更好的方法吗?让任务不断地为不经常发生的事情工作对我来说似乎是错误的。
编辑:我是 C# 的新手,所以如果有什么明显的地方请毫不犹豫地指出来。
更新:
根据响尾蛇链接的 MS 的精彩教程,我向列表的添加功能添加了一个简单的事件。所以:
public delegate void ChangedEventHandler(object sender, EventArgs e);
public class listWithChanges<T> : List<T>
{
public event ChangedEventHandler Changed;
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
Changed(this, e);
}
public new void Add (T item)
{
base.Add(item);
OnChanged(EventArgs.Empty);
}
}
并通过委托添加到我的输出中
responses.Changed += ((o, e) => {
int index = Form.ActiveForm.Controls.IndexOfKey("responseBox");
Form.ActiveForm.Invoke((MethodInvoker) (() => Form.ActiveForm.Controls[index].Visible = true));
Form.ActiveForm.Invoke((MethodInvoker) (() => Form.ActiveForm.Controls[index].Text = responses[responses.Count - 1]));
});
事件将是一个很好的解决方案。
事件是 Observer 模式的实现,其中源(网络通信)警告它的观察者(在您的示例中调用任务的任何人)发生了什么事。
效率高得多,因为它不会在无限循环中浪费 CPU 用法,该方法仅在客户端响应时执行。
C# 对事件有很好的支持,考虑阅读 MS Tutorial(最初由 Sidewinder94 发布)。
如果您不想对代码进行重大重构,可以为您的 responses
集合使用 阻塞队列,这样您的在等待项目出现在队列中时读取线程块。
等待某个东西出现在阻塞队列中消耗零 CPU。 (技术上不为零,但仍然不明显。)
我为我的每个网络通信创建了一个线程,每当他们收到来自客户端的回复时,他们就会将响应添加到列表中。我正在执行下面的任务以查看是否有任何通信进来。它在屏幕上显示最近的一个。
Task task = new Task(
(() =>
{
int i = 0;
while (true)
{
if (responses.Count > i){
Debug.WriteLine(responses[i]);
int index = Form.ActiveForm.Controls.IndexOfKey("responseBox");
Form.ActiveForm.Invoke((MethodInvoker) (() => Form.ActiveForm.Controls[index].Visible = true));
Form.ActiveForm.Invoke((MethodInvoker) (() => Form.ActiveForm.Controls[index].Text = responses[i]));
i++;
}
}
}));
task.Start();
我的问题是;我有更好的方法吗?让任务不断地为不经常发生的事情工作对我来说似乎是错误的。
编辑:我是 C# 的新手,所以如果有什么明显的地方请毫不犹豫地指出来。
更新:
根据响尾蛇链接的 MS 的精彩教程,我向列表的添加功能添加了一个简单的事件。所以:
public delegate void ChangedEventHandler(object sender, EventArgs e);
public class listWithChanges<T> : List<T>
{
public event ChangedEventHandler Changed;
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
Changed(this, e);
}
public new void Add (T item)
{
base.Add(item);
OnChanged(EventArgs.Empty);
}
}
并通过委托添加到我的输出中
responses.Changed += ((o, e) => {
int index = Form.ActiveForm.Controls.IndexOfKey("responseBox");
Form.ActiveForm.Invoke((MethodInvoker) (() => Form.ActiveForm.Controls[index].Visible = true));
Form.ActiveForm.Invoke((MethodInvoker) (() => Form.ActiveForm.Controls[index].Text = responses[responses.Count - 1]));
});
事件将是一个很好的解决方案。
事件是 Observer 模式的实现,其中源(网络通信)警告它的观察者(在您的示例中调用任务的任何人)发生了什么事。
效率高得多,因为它不会在无限循环中浪费 CPU 用法,该方法仅在客户端响应时执行。
C# 对事件有很好的支持,考虑阅读 MS Tutorial(最初由 Sidewinder94 发布)。
如果您不想对代码进行重大重构,可以为您的 responses
集合使用 阻塞队列,这样您的在等待项目出现在队列中时读取线程块。
等待某个东西出现在阻塞队列中消耗零 CPU。 (技术上不为零,但仍然不明显。)