.net - VB.NET:线程函数调用比直接调用函数慢?

标签 .net vb.net multithreading delegates

我有一个函数,我在 Sub 中执行大量数据库操作。直接调用时的操作如下:

执行进程()

运行大约需要 11 秒。

但是,如果我创建一个委托(delegate),并使用 BeginInvoke() 调用子程序,则执行相同的过程需要 40 多秒。

这是线程代码:

protected del 作为 ProcessDelegate
protected 委托(delegate)子 ProcessDelegate()
...
del = 新 ProcessDelegate(AddressOf SELocal.ExecJob)
将 cb 调暗为新的 AsyncCallback(AddressOf Me.ExecJobComplete)
del.BeginInvoke(cb, del)

任何人都知道什么可能导致函数在新线程中花费更长的时间,而不是直接调用?

谢谢

最佳答案

Anyone know what may cause a function to take longer inside a new thread, rather than calling directly?



当代码使用配置为在单线程单元 (STA) 中运行的 COM 对象并满足以下其他条件之一时,所有条件都相同是从一个线程到另一个线程执行速度较慢的最常见原因之一。
  • 它是从实例化它的线程以外的线程调用的。
  • 它是从配置为在多线程单元 (MTA) 中运行的线程调用的。

  • 每次访问对象时都会发生昂贵的编码(marshal)操作。慢 4 倍是这个问题的一个完全合理的症状。如果您继续使用 BeginInvoke,解决此问题将非常困难。调用机制。原因是该机制使用 ThreadPool不能轻易(或根本)切换到 STA 模式的执行线程。

    我认为您最好的选择是创建自己的线程池,您可以在其中控制公寓状态。这并不像听起来那么难。以下代码使用 BlockingCollection数据结构在 .NET 4.0 中可用或作为 Reactive Extensions 的一部分下载。

    注意:您必须自己添加代码强化以使其更健壮,支持正常关闭等。
    public class CustomThreadPool
    {
        private BlockingCollection<WorkItem> m_WorkItems = new BlockingCollection<WorkItem>();
    
        public CustomThreadPool(int poolSize)
        {
            for (int i = 0; i < poolSize; i++)
            {
                var thread = new Thread(Run);
                thread.IsBackground = true;
                thread.SetApartmentState(ApartmentState.STA);
                thread.Start();
            }
        }
    
        public void QueueUserWorkItem(WaitCallback callback, object state)
        {
            m_WorkItems.Add(new WorkItem { Callback = callback, State = state });
        }
    
        private void Run()
        {
            while (true)
            {
                WorkItem item = m_WorkItems.Take();
                item.Callback(item.State);
            }
        }
    
        private class WorkItem
        {
            public WaitCallback Callback { get; set; }
            public object State { get; set; }
        }
    }
    

    然后而不是调用 BeginInvoke在委托(delegate)上你会这样做。
    myThreadPool.QueueUserWorkItem((state) => { myDelegate(/* arguments */); }, null);
    

    但要记住的最重要的事情是 COM 对象必须在 STA 线程上实例化,并且必须从该线程进行所有进一步的访问。与此的任何偏差都将导致编码操作。如果您选择在此答案中使用该方法,则必须在委托(delegate)中创建 COM 对象。

    关于.net - VB.NET:线程函数调用比直接调用函数慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3713458/

    相关文章:

    c# - 关于.net core应用的轻量级

    .net - 如何使用 ILMerge 将多个程序集合并为一个程序集

    c# - Asp.Net 应用程序中的 Mathematica .Net/Link

    vb.net - 以编程方式设置 ListView 中的所选项目后,箭头键不起作用

    java - 第二个线程退出而不是向前循环

    c# - .NET C# 多线程

    c# - 尝试使用 C# 执行命令行脚本时出现 System.InvalidOperation 异常

    .net - 在 VB.NET 源代码中查找未使用的 'Imports' 语句

    .net - 我收到错误 "Application"在命名空间 'microsoft.office.interop.excel' 中不明确

    c - openmp 排序临界区