Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在c#中线程工作的最佳方式是什么?_C#_.net_Multithreading - Fatal编程技术网

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

在c#中线程工作的最佳方式是什么?,c#,.net,multithreading,C#,.net,Multithreading,在c#中执行工作(方法)的最佳方式是什么 例如: 假设我有一个表单,希望从db加载数据 My form controls: - dataGridView (to show data from DB), - label (loading status) and - button (start loading). 当我点击按钮时,我的表单将被冻结,直到任务完成。此外,在任务完成之前,加载状态不会更改。我认为异步线程将是答案 所以我的问题是:处理这个问题的最好方法是什么?我知道有很多关于

在c#中执行工作(方法)的最佳方式是什么

例如:

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

My form controls: 
 - dataGridView (to show data from DB), 
 - label (loading status) and 
 - button (start loading).
当我点击按钮时,我的表单将被冻结,直到任务完成。此外,在任务完成之前,加载状态不会更改。我认为异步线程将是答案

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

你如何解决这类问题


致以最诚挚的问候。

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

您可以使用这种模式:-

    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);
        });
    }
private void刷新按钮\u单击(对象发送者,事件参数e)
{
MessageLabel.Text=“正在工作…”;
RefreshButton.Enabled=false;
ThreadPool.QueueUserWorkItem(委托(对象状态)
{
//你在这里工作吗
//例如。
对象数据源=GetData();
调用((操作)委托(对象obj)
{
//gridview也应该在UI线程中访问
//例如。
MyGridView.DataSource=obj;
MessageLabel.Text=“完成。”;
RefreshButton.Enabled=true;
},数据源);
});
}

没有通用的“最佳”线程工作方式。恐怕你得尝试不同的做事方式

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

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

  • 执行不应阻塞UI的长时间运行操作
  • 。。。完成后,在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);
                                             });
        }
    }
    

    您无法通过在派生线程中运行的代码访问控件-框架不允许这样做,这就解释了您所遇到的错误


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

    谢谢您的回答。在何处调用Control.Invoke()?我收到一个错误:跨线程操作无效:控件“dataGridView”是从创建它的线程以外的线程访问的。我已将代码转换为Winforms。请注意,您还必须在UI线程中操作gridview,因为它是一个UI元素。这将消除您看到的运行时异常。我已将框架更改为3.5。现在它起作用了。谢谢你,亚当!谢谢你的回答。是的,我正在使用win窗体和.NET2.0。我尝试了AdamRalph的答案和get中的ThreadPool,错误:跨线程操作无效:控件“dataGridView”是从创建它的线程以外的线程访问的。一旦将工作移动到另一个线程上,它就不能再直接访问用户界面(因此跨线程调用)。您需要使用Control.Invoke()或Control.BeginInvoke()将控件传递回UI线程,要求它为您更新UI。这就是为什么
    BackgroundWorker
    类很好;它会在UI线程上引发事件,因此不需要
    Invoke()
    。谢谢您的回答。如果没有.NET2.0中的lambda,我如何使用它?Mark,现在我在.NET3.5上。我遇到错误:使用泛型类型“System.Action”需要“1”类型参数。做什么?“操作”是具有一个参数的通用操作;我发布的代码只使用了没有参数的“Action”。看起来你想用行动代替行动。嘿,马克。我试过你的解决方案,效果很好。您能演示一下如何从ExecuteWithContinuation部分返回一些值吗?假设我有一些需要在完成时更新的东西(inti),并且想要更改变量。怎么做?在c#中线程工作的最佳方式是什么?小心实际上,
    CrossThreadException
    只会在调试模式下抛出。
    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();
                                        };
                        });
    }