C# 从SQL Server返回进程信息
总之,我有一些复杂的C#代码(Windows窗体),其中大量嵌入了对SQL Server的调用(2008 R2或更高版本是假定的服务器版本)。就目前而言。代码是串行的,我被要求对其进行多线程处理。这个多线程处理过程现在特别与代码的昂贵部分相关,即代码执行“繁重”操作的地方。大部分工作是通过SQL Server查询完成的 我即将开始多线程处理主处理器,它处理对SQL Server的调用。我想通过“SQL线程”的进度向用户提供信息,因为SQL过程可能非常长。我想知道我的方法听起来是否合理,或者是否有更好的方法。我的方法如下:(注意:下面的代码只是我在尝试使用实际代码之前构建的一个小示例) A.从主窗体上的按钮单击事件启动C# 从SQL Server返回进程信息,c#,sql,multithreading,C#,Sql,Multithreading,总之,我有一些复杂的C#代码(Windows窗体),其中大量嵌入了对SQL Server的调用(2008 R2或更高版本是假定的服务器版本)。就目前而言。代码是串行的,我被要求对其进行多线程处理。这个多线程处理过程现在特别与代码的昂贵部分相关,即代码执行“繁重”操作的地方。大部分工作是通过SQL Server查询完成的 我即将开始多线程处理主处理器,它处理对SQL Server的调用。我想通过“SQL线程”的进度向用户提供信息,因为SQL过程可能非常长。我想知道我的方法听起来是否合理,或者是否有
BackgroundWorker
线程
Bgw = new BackgroundWorker { WorkerReportsProgress = true, WorkerSupportsCancellation = true };
Bgw.DoWork += new DoWorkEventHandler(Bgw_DoWork);
Bgw.ProgressChanged += new ProgressChangedEventHandler(Bgw_ProgressChanged);
Bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Bgw_RunWorkerCompleted);
Bgw.RunWorkerAsync();
B.从Bgw_DoWork
事件中,我启动了我的SQL方法,它位于类HeavyWork
中
void Bgw_DoWorkSQL(object sender, DoWorkEventArgs e)
{
Hw = new HeavyWork(this, ref Bgw, ref e);
Hw.SQLProc();
return;
}
C.从Hw.SQLProc
内的BackgroundWorker
(这次不是BackgroundWorker
)启动另一个后台线程,以捕获SQL查询的进度并方便取消SQL Server查询
// Globals.
private bool bConnOpen = false;
private SqlConnection conn = null;
private Form _MainForm;
private BackgroundWorker _Bgw;
private DoWorkEventArgs _e;
public void SQLProc()
{
bool bConnOpen = false;
const string strSqlConnMaster = "Data Source = localhost; Initial Catalog = RMH1006DHFinal; Integrated Security " + "= True; MultipleActiveResultSets = True; Connection Timeout = 0";
const string strSQL = "DBCC CHECKDB"; // Expensive SQL Non-Query.
try
{
// Create new SQL connection.
conn = new SqlConnection(strSqlConnMaster);
// Execute the SQL Non-Query.
conn.Open();
bConnOpen = true;
// Start another thread to get user information and for cancellation purposes.
Thread SQLThread = new Thread(myMethod); // This is not working.
SQLThread.IsBackground = true;
SQLThread.Start();
// Now run big query.
_Bgw.ReportProgress(0, String.Format("Processing SQL Command '{0}'...", strSQL));
ExecNonQuery(conn, strSQL);
conn.Close();
bConnOpen = false;
return;
}
catch (Exception)
{
throw;
}
finally
{
if (bConnOpen)
conn.Close();
}
}
总之,我想在单独的BackgroundWorker
上启动昂贵的SQL查询。在BackgroundWorker
线程上调用的方法中(某些查询使用SQL连接发送,称之为SqlConnection conn
),启动另一个线程
,该线程使用单独的SqlConnection connNew
进入另一种方法,该方法在conn
上检索有关主进程的信息
我想知道这样做有效吗?另外,如果可以从BackGroundWorker
启动新的线程
s,因为上面的代码没有在新线程上启动myMethod
方法
提前感谢大家。如果您想从背景线程中衍生出一个新线程,那很好。但是,正如您所说的,如何设置它在当前状态下不起作用
Thread SQLThread = new Thread(myMethod); // This is not working.
…应该变成
Thread SQLThread = new Thread(new ThreadStart(myMethod));
...
……或者干脆
Thread SQLThread = new Thread(()=>myMethod());
如果我理解正确,您希望指示进度,但不能,因为
execonquery
阻塞
作为一种良好的实践,如果db调用可能需要一秒钟以上的时间,我不会为此使用BackgroundWorker,因为BW使用线程池线程。相反,我会使用一个新线程,或者,如果您在.NET4.0上,则使用带有TaskCreationOptions.LongRunning
的任务
回到您的进度报告:您的db调用阻塞,因此您可以显示的唯一进度是正在运行或已完成,因此我将显示某种字幕进度指示器。我会使用计时器从UI线程控制这一点-你不想仅仅为了制作动画而启动线程,而且你还是想进入UI线程。嗨,乔治,谢谢你的评论。我现在想知道为什么
SQLThread.Start()代码>在这种情况下不起作用?在第二个例子中,Thread()=>myMethod())
委托被声明并立即分离。第一个是ThreadStart,它只是简单地声明它,并且它仍然需要一个Thread.StartGeorge,谢谢您的帮助。然而,尽管上面的建议很有帮助,但它们并没有回答我的问题——事实上,我的代码做的是正确的,但优先级处于其默认级别——这意味着线程在主SQL查询启动之前不会被取消,这就是我没有看到它的原因。再次感谢。你好,尼克,谢谢你的回复。我的想法是使用连接a在一个单独的线程a上启动昂贵的SQL查询,但也启动另一个线程B,该线程B使用连接B从SQL Server获取进度完成值,使用会话id={0}的sys.dm_exec_请求中的选择完成百分比
此处的会话id可以使用连接A从线程B确定。这就提出了一个问题;能否同时使用两个不同的连接访问SQL Server?另外,我不确定我是否理解你关于BGW线程的说法——这就是重点,不是吗?@Killercam:docs说,这只适用于有限的一组SQL语句。另外,在服务器上执行SQL语句时,无法报告其进度。BGW是在.NET2.0中引入的-我现在在大多数情况下都会避免使用它,特别是当您使用TPL时。我知道它的使用是有限的。谢谢你是说现在不应该使用BackgroundWorker
?我有Joesph Albahari的书C#4.0,简而言之,在使用BackgroundWorker
执行长时间运行的任务时,他没有说明任何此类问题。它不仅仅是基于事件的异步模式的通用实现。此外,请检查SBGW是否可以并且应该用于此类目的。