在c#中使用线程工作(方法)的最佳方法是什么?
例如:
假设我有一个表单并希望从db加载数据。
My form controls:
- dataGridView (to show data from DB),
- label (loading status) and
- button (start loading).
当我点击按钮时,表单被冻结,直到任务完成。在任务完成之前,加载状态也不会改变。我认为异步线程会是答案吗?
所以我的问题是:处理这个问题的最佳方法是什么?我知道有很多关于线程的东西,但是它们之间的区别是什么?你如何使线程安全?
你如何解决这类问题?
最诚挚的问候。
答案 0 :(得分:7)
如果使用Windows窗体,则应查看BackrgroundWorker。更一般地说,使用ThreadPool类通常很有用。最后,值得一看新的.NET 4的Parallel类。
答案 1 :(得分:3)
没有通用的'最佳'方式来处理工作。你只需要尝试不同的做事方式,我担心。
我特别喜欢杰里米·D·米勒(Jeremy D. Miller)描述的at this page的延续思想(向下滚动以找到“延续”部分)。它非常优雅,意味着编写很少的样板代码。
基本上,当您使用Func参数调用“ExecuteWithContinuation”时,该函数将异步执行,然后在完成时返回一个操作。然后将操作编组回您的UI线程以充当延续。这使您可以快速将操作拆分为两位:
需要一点时间来适应,但它很酷。
public class AsyncCommandExecutor : ICommandExecutor
{
private readonly SynchronizationContext m_context;
public AsyncCommandExecutor(SynchronizationContext context)
{
if (context == null) throw new ArgumentNullException("context");
m_context = context;
}
public void Execute(Action command)
{
ThreadPool.QueueUserWorkItem(o => command());
}
public void ExecuteWithContinuation(Func<Action> command)
{
ThreadPool.QueueUserWorkItem(o =>
{
var continuation = command();
m_context.Send(x => continuation(), null);
});
}
}
然后你就这样使用它(原谅格式......)
public void DoSomethingThatTakesAgesAndNeedsToUpdateUiWhenFinished()
{
DisableUi();
m_commandExecutor.ExecuteWithContinuation(
() =>
{
// this is the long-running bit
ConnectToServer();
// This is the continuation that will be run
// on the UI thread
return () =>
{
EnableUi();
};
});
}
答案 2 :(得分:1)
您可以使用这种模式: -
private void RefreshButton_Click(object sender, EventArgs e)
{
MessageLabel.Text = "Working...";
RefreshButton.Enabled = false;
ThreadPool.QueueUserWorkItem(delegate(object state)
{
// do work here
// e.g.
object datasource = GetData();
this.Invoke((Action<object>)delegate(object obj)
{
// gridview should also be accessed in UI thread
// e.g.
MyGridView.DataSource = obj;
MessageLabel.Text = "Done.";
RefreshButton.Enabled = true;
}, datasource);
});
}
答案 3 :(得分:0)
您无法从分离线程中运行的代码访问您的控件 - 框架不允许这样做,这解释了您获得的错误。
您需要在非表单对象中缓存从db检索到的数据,并在后台工作线程完成后使用该对象的数据填充UI(并处理同步以访问该对象)。