在主线程上调用代表 - 没有UI



我一直在阅读各种与我想做的类似的问题,但与众不同,以至于它们似乎不适用。我拥有的是一个C#项目,以创建CLR存储过程。我正在通过多线程通过多线程来改善CLR存储过程的性能。(它具有一组嵌套的循环,在最内部的循环中,我称为Parallel.ForEach以在自己的线程上运行它们。(好吧,有时,完成的处理需要针对数据库执行查询。这是使用首先启动存储过程的上下文连接完成的。这是我的问题。SQL Server不会让您从子线程访问上下文连接。如果要访问上下文连接,则必须在主线程上执行。

由于这不是Winforms项目,所以我无法使用 begininvoke 。(而且我知道WPF应用程序也有类似的命令。(我已经看到了几篇文章,讨论了使用 synchronizationContext 来执行此操作的文章。但是我的主线程没有参考的 synchronizationContext 。(我认为这是由第一个控件放在线程上的?(我需要弄清楚如何将执行载体回到主线程中以访问上下文连接。我仍然对使用多线程应用程序合作有些陌生。因此,如果我的术语使用量很差或不精确,我深表歉意。

谢谢。

编辑:

因此,根据评论和答案,到目前为止,我尝试进行一些更改,但恐怕他们不起作用,或者我只是没有得到任何东西。因此,我认为我会发布一些简化的代码,以此作为我当前正在做的事情的示例。(请记住,此示例不起作用,因为查询执行是在子线程上进行的,只有主线程才能使用上下文连接。(

public class MyDatabaseProject
{
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static int MyClrStoredProcedure(...)
    {
        ProcessingEngine engine = new ProcessingEngine();
        engine.SomeQueryEvent += this.HandleSomeQueryEvent;
        ...  // Gather up some data to process.
        DataTable results = engine.Compute(...);
        ...  // Save the computed results DataTable.
    }
    private static void HandleSomeQueryEvent(object Sender, MyEventArgs e)
    {
        SqlConnection contextConn = new SqlConnection("context connection=true");
        contextConn.Open();
        foreach (string query in e.QueriesToExecute)
        {
            // Use the contextConnection to execute the query and store the results in MyEventArgs.
        }
        contextConn.Close();
    }
}
public class ProcessingEngine
{
    public DataTable Compute(...)
    {
        ... // Do stuff
        foreach(var timingIndicator in SomeCollection)
        {
            ... // Do stuff
            Parallel.ForEach(FormulasToProcessNow, new ParallelOptions { MaxDegreeOfParallelism = this.ConcurrencyLevel }, r =>
            {
                ... // Do stuff, including raising "SomeQueryEvent"
                ... // Do stuff with the results of the queries.
            });
        }
    }
}

那么,让我感到困惑的是如何以一种可以正常工作的方式整合您的建议(例如contrentqueue和utoresetevent(。希望此代码有用。再次感谢。

尝试基于 @0liveradam8的评论的此食谱。

  1. 创建线程安全队列,例如同意。
  2. 设置所有线程a'runnin';每个线程将分配一个等待手柄;在这种情况下
  3. 当每个线程必须访问上下文时,招募包含三个信息的结构:使用上下文,线程的等待手柄以及存储Func的结果的Func
  4. 在循环中的主线程中,将项目销售,致电Func,将结果存储在项目中,然后发出信号。

上面的将元帅调用到主线程的上下文,并将其返回到呼叫线程。如果线程需要多次执行此操作,那没关系,因为您的等待句柄将自动重置为不信号,因此可以重复使用。

线程将在使用上下文时被阻止,这意味着并发有所降低,但您仍然可能会得到您的需求,并且它将是安全的。

有原因您需要使用上下文连接吗?您是使用任何特定于会话的功能,例如是现有事务的一部分,或从现有临时表中读取的一部分,还是使用CONTEXT_INFO/SESSION_CONTEXT

有什么原因是您只是不使用常规/外部连接吗?

(这些问题通过以下引用的陈述回答(

我们希望它能使用用户的安全性,连接设置等运行。此外,如果我尝试从代码中打开连接,SQL Server会引起异常。因此,老实说,我没有给出太多思考。不允许打开另一个连接,我们还是想使用上下文连接。这就是我们所做的。

  1. 使用用户的安全运行很容易:

    1. 如果用户是SQL Server登录,请在ConnectionString中传递这些凭据。如果有很多用户可以执行此代码,这可能会更加困难,尽管您可以将用户作为输入参数传递给SQLCLR存储的过程,并从这些过程中构建连接字符串。
    2. 如果用户是Windows登录,请实现模仿。您可以从SqlContext获取Windows安全主体(或其他(。然后做:

      using(impersonationContext = principal.Impersonate())
      {
        connection.Open();
        ...
        impersonationContext.Undo();
      }
      

      这不是准确的,但是很接近。

  2. 不确定打开常规连接时为什么会得到例外,除非连接字符串有所不到。确切的(和完整(错误消息将有所帮助,尽管听起来您现在已经解决了这个问题。

好吧,所以我们实际上是这样做的。对于这些查询,我们不需要上下文连接。因此,我们能够摆脱打开新的连接,而不是弄清楚如何有效切换线程。

好!很高兴听到它毕竟奏效了😺。由于上下文连接不是必需的,因此看来要花费更多的时间/精力来弄清线程开关要比值得的。而且,该代码希望比您最终得到的更复杂(即更难维护(。

我怀疑,如果我们从一开始就对此进行了架构,将这些查询运行在主线程上,那不是这样的问题。但这似乎可以完成工作。

是的,如果您从一开始就计划了这一部分,可能会不那么复杂。但是,这将引入有关这种单数连接的强度点,这将降低性能(即使只是稍微(。即使上下文连接的打开/关闭速度比常规连接更快,但根据查询获得结果需要多长时间,各种线程的等待可能会远远超过几毫秒来通过建立常规的额外的毫秒。连接。如果您需要特定于会话的功能(即在主动交易中工作,使用本地临时对象,使用CONTEXT_INFO和/或SESSION_CONTEXT等(,那是值得的,也可能值得。


有关与SQLCLR合作的更多信息,请访问:sqlclr info

相关内容

  • 没有找到相关文章

最新更新