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

VB.NET:线程函数调用比直接调用函数慢?,.net,vb.net,multithreading,delegates,.net,Vb.net,Multithreading,Delegates,我有一个函数,其中我在Sub中执行大量数据库操作。直接调用该函数时的操作如下: ExecProcess() 运行大约需要11秒 但是,如果我创建一个委托,并使用BeginInvoke()调用子委托,同样的过程需要40秒才能执行 以下是线程代码: Protected del As ProcessDelegate Protected Delegate Sub ProcessDelegate() ... del = New ProcessDelegate(AddressOf SE

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

ExecProcess()

运行大约需要11秒

但是,如果我创建一个委托,并使用BeginInvoke()调用子委托,同样的过程需要40秒才能执行

以下是线程代码:

Protected del As ProcessDelegate Protected Delegate Sub ProcessDelegate() ... del = New ProcessDelegate(AddressOf SELocal.ExecJob) Dim cb As New AsyncCallback(AddressOf Me.ExecJobComplete) del.BeginInvoke(cb, del) 受保护的del作为ProcessDelegate 受保护的委托子进程委托() ... del=新的ProcessDelegate(SELocal.ExecJob的地址) Dim cb作为新的AsyncCallback(AddressOf Me.ExecJobComplete) del.BeginInvoke(cb,del) 有人知道什么会导致函数在新线程中花费更长的时间,而不是直接调用吗


谢谢

正如Henk指出的,您实际上只是在使用普通线程池的包装器,所以所有正常的线程规则都适用。我强烈建议您寻找锁争用或其他情况,其中两个线程正在访问相同的信息,并为谁拥有这些信息而争吵

如果那不起作用

有人担心,除非调用EndInvoke,否则BeginInvoke可能会导致资源泄漏。那么,长时间启动是在线程的第一次繁殖上还是在后续线程上?这曾经是我的一个问题,但并不总是一个问题。它最终将在没有EndInvoke的情况下得到GC'ed,但不会立即得到

编辑:还有一些想法:您是否对不同的线程(包括主线程)使用相同的连接?或者,您的连接池是否已用完可用的连接(服务器端或客户端),而您最终在等待可用连接时被阻塞

此外,有时人们会对数据访问进行编码,使事务处于静态/共享状态,从而使每个事务只能有一个活动的事务。这将是另一个需要寻找的东西

有人知道什么会导致功能丧失吗 要在新线程中花费更长的时间, 而不是直接打电话

当代码使用配置为在单线程单元(STA)中运行的COM对象并满足以下其他条件之一时,就会出现从一个线程到另一个线程执行速度较慢的最常见原因之一

  • 它不是从实例化它的线程调用的
  • 它是从配置为在多线程单元(MTA)中运行的线程调用的
昂贵的封送处理操作通常发生在对对象的每次访问上。速度慢4倍是该问题的一个完全合理的症状。如果继续使用
BeginInvoke
调用机制,解决此问题将非常困难。原因是该机制使用
ThreadPool
线程执行,无法轻松(或根本无法)切换到STA模式

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

注意:您必须自己添加代码强化,以使其更加健壮,支持优雅地关闭,等等


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

我在线程函数中使用了许多连接方法,并且实际上也调用COM对象和方法。我怎样才能确定这是否真的导致了我的问题?@aronh:我在回答中添加了更多的信息。事实上,您已经承认您正在使用COM对象,这很可能是导致速度缓慢的原因。我已经用计时器等调试了代码,以确保它不是生成暂停或类似的情况。。代码运行。。只是慢了很多。我没有发多个线程或类似的东西,只是一个调用。我在调用中使用了一个新连接,但是我正在尝试将信息共享回主线程(状态信息)。。我正在调用的方法位于类内。。该类设置属性,我在线程化方法执行时读取它们作为状态。这是否会导致锁争用?任何在两个线程之间访问值的尝试都会导致争用。此外,在单步执行代码时几乎不可能看到。我不是一个真正的VB.Net爱好者,VB.Net中没有volatile关键字,但您应该始终同步或以其他方式确保同步线程之间共享的任何对象的访问。您还可以看看以下内容:
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; }
    }
}
myThreadPool.QueueUserWorkItem((state) => { myDelegate(/* arguments */); }, null);