【发布时间】:2019-05-24 19:40:53
【问题描述】:
我一直在阅读各种各样的问题,这些问题与我正在尝试做的事情相似,但又足够不同,以至于它们似乎并不适用。我拥有的是一个用于创建 CLR 存储过程的 C# 项目。我正在通过多线程来提高 CLR 存储过程的性能。 (它有一组嵌套循环,在最里面的循环中我调用Parallel.ForEach 以在它们自己的线程上运行它们。)嗯,有时完成的处理需要对数据库执行查询。这是使用首先启动存储过程的上下文连接来完成的。这是我的问题。 SQL Server 不允许您从子线程访问上下文连接。如果要访问上下文连接,则必须在主线程上执行。
由于这不是 WinForms 项目,我无法使用 BeginInvoke。 (而且我知道 WPF 应用程序也有类似的命令。)而且我已经看过几篇讨论使用 SynchronizationContext 来执行此操作的帖子。但是我的主线程没有要引用的 SynchronizationContext。 (我认为这是由放置在线程上的第一个控件创建的?)我需要弄清楚如何将执行编组回主线程,足以访问上下文连接。我对使用多线程应用程序仍然有些陌生。因此,如果我的术语使用不当或不准确,我深表歉意。
谢谢。
编辑:
所以,根据 cmets 和答案,到目前为止,我尝试进行一些更改,但我担心它们要么不起作用,要么我没有得到任何东西。所以我想我会发布一些简化的代码作为我目前正在做的事情的一个例子。 (请记住,此示例不起作用,因为查询执行发生在子线程上,并且只有主线程可以使用上下文连接。)
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.
});
}
}
}
所以让我感到困惑的是如何以一种可行的方式整合您的建议(例如 ConcurrentQueue 和 AutoResetEvent)。希望这段代码有用。再次感谢。
【问题讨论】:
-
你能不能有一个队列来在主线程上存储委托,让子线程添加他们想要调用的任何委托,最后让主线程循环遍历列表并执行委托?
-
我不确定这将如何工作。子线程需要它们尝试执行的 SQL 查询的结果才能完成它们的处理。
-
您可以在主线程中使用额外的数据结构来存储查询结果,并让子线程从中获取结果
-
@DeadZone ,您是否有理由需要 使用上下文连接?您是否使用任何特定于会话的功能,例如作为现有事务的一部分,或从现有临时表中读取,或使用
CONTEXT_INFO/SESSION_CONTEXT?您是否有理由不使用常规/外部连接? -
@Solomon,好的,所以我们实际上最终选择了这个。对于这些查询,我们不需要上下文连接。所以我们能够摆脱打开新连接,而不是弄清楚如何有效地切换线程。我怀疑,如果我们从一开始就将其设计为在主线程上运行这些查询,那么它就不会成为这样的问题。但这似乎完成了工作。所以谢谢你。
标签: c# sql-server multithreading database-connection sqlclr