繁体   English   中英

在c#中使用线程工作的最佳方法是什么?

[英]What is the best way to thread work in c#?

在c#中使用线程工作(方法)的最佳方法是什么?

例如:

假设我有一个表单,并希望从db加载数据。

My form controls: 
 - dataGridView (to show data from DB), 
 - label (loading status) and 
 - button (start loading).

当我单击按钮时,我的表单将被冻结,直到任务完成。 在任务完成之前,加载状态也不会改变。 我认为异步线程会是答案吗?

所以我的问题是:处理这个问题的最佳方法是什么? 我知道有很多关于线程的东西,但是它们之间的区别是什么?你如何使线程安全?

你是如何解决这类问题的?

最好的祝福。

如果使用Windows窗体,则应查看BackrgroundWorker 更一般地说,使用ThreadPool类通常很有用。 最后,值得一看的是新的.NET 4的Parallel类。

没有通用的“最佳”方式来处理工作。 你只需要尝试不同的做事方式,我担心。

我特别喜欢Jeremy D. Miller 在本页描述的延续思想(向下滚动以找到“延续”部分)。 它非常优雅,意味着编写非常少的样板代码。

基本上,当您使用Func参数调用“ExecuteWithContinuation”时,该函数将异步执行,然后在完成时返回一个操作。 然后将操作编组回您的UI线程以充当延续。 这允许您快速将操作拆分为两位:

  1. 执行不应阻止UI的长时间运行操作
  2. ...完成后,更新UI线程上的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();
                                    };
                    });
}

你可以使用这种模式: -

    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);
        });
    }

您无法从分离线程中运行的代码访问您的控件 - 框架不允许这样做,这解释了您获得的错误。

您需要在非表单对象中缓存从db检索的数据,并在后台工作线程完成后使用该对象的数据填充UI(并处理访问该对象的同步)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM