System.Diagnostic.Process的线程池问题 [英] Thread pool problem with System.Diagnostic.Process

查看:90
本文介绍了System.Diagnostic.Process的线程池问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用ThreadPool对名为RunScripts的方法进行多次调用.线程数由要运行的sql脚本文件数维护.如果有4个要运行的sqlscript,则我对ThreadPool.QueueUserWorkItem进行了4次调用.在RunScripts方法中,我正在使用System.Diagnostic.Process运行sql脚本,如代码所示.该流程具有两个事件处理程序,分别是OutPutDataReceived和ErrorDataRecieved.在这两个事件中,我只是在控制台中打印消息.我已经设置了ThreadPool.SetMinThreads = 4和ThreadPool.SetMaxThreads = 10.

在代码中,我的进程完成工作后,就立即调用了executorProcess.CancelOutputRead()和executorProcess.CancelErrorRead().如果我没有记错的话,那么只有在有任何标准output/error的情况下调用两个事件之后,程序执行才会到达这些行.我的脚本在3或4秒钟内完成执行.我的问题是没有为每个线程调用OutputDataReceived和ErrorDataReceived事件.异步读取在调用两个事件之前被取消.但是,如果我增加MinThreads和MasThreads,则在调试点到达CancelOutputRead()和CancelErrorRead()之前调用这两个事件.
当我从代码中删除executorProcess.CancelOutputRead()和executorProcess.CancelErrorRead()时,每个标准输出和错误都会被打印出来.我不确定为什么线程数较少时为什么它不起作用.

I am using ThreadPool to make multiple calls to a method called RunScripts. Number of threads are maintained by a count of number of sql scriptfile to run. If there are 4 sqlscripts to run then I make call to ThreadPool.QueueUserWorkItem 4 times and son on. In the RunScripts method, I am using System.Diagnostic.Process to run the sql scripts as shown is the code. The Process has two event handlers namely OutPutDataReceived and ErrorDataRecieved. In both of the events, I am simply printing the message in console. I have set the ThreadPool.SetMinThreads=4 and ThreadPool.SetMaxThreads=10.

In the code, I have called executorProcess.CancelOutputRead() and executorProcess.CancelErrorRead() as soon as my process finish the work. If I am not wrong the program execution reach these lines only after the two events are called if there are any standard output/error . My scripts finish execution within 3 or 4 seconds. My problem here is OutputDataReceived and ErrorDataReceived events are not called for every threads. Asynchronous reads are being cancelled before the two events are invoked.However, if I increase the MinThreads and MasThreads then the two events are called before the debug point reach CancelOutputRead() and CancelErrorRead().

when I removed the executorProcess.CancelOutputRead() and executorProcess.CancelErrorRead() from the code then every standard ouput and error are being printed. I am not sure why it is not working when there are less number of threads.

Private void RunScripts()
{

      // Start SQLCMD process.
                ProcessStartInfo psi = new ProcessStartInfo();
                psi.FileName = "SQLCMD.EXE";
                string args = "-S " + this.Server;
                if (string.IsNullOrEmpty(this.UserName)) args += " -E";
                else args += " -U " + this.UserName;
                if (!string.IsNullOrEmpty(scriptFile.Database))
                    args += " -d " + scriptFile.Database;
                if (string.IsNullOrEmpty(this.Password))
                    args += " -i " + scriptFilePath;
                else
                    args += " -P " + this.Password + " -i " + scriptFilePath;
                psi.Arguments = args;
                psi.RedirectStandardOutput = true;
                psi.RedirectStandardError = true;
                psi.UseShellExecute = false;

                using (Process executorProcess = Process.Start(psi))
                {
                    executorProcess.EnableRaisingEvents = true;
                    executorProcess.OutputDataReceived +=
                        new DataReceivedEventHandler(
                            this.executorProcess_DataReceived);
                    executorProcess.ErrorDataReceived +=
                        new DataReceivedEventHandler(executorProcess_ErrorDataReceived);
        
                    executorProcess.BeginOutputReadLine();
                    executorProcess.BeginErrorReadLine();
                    bool exited = false;
                    while (!exited)
                    {
                        exited = executorProcess.WaitForExit(60000);
                        if (!exited && this.StopSignal)
                        {
                            try { executorProcess.Kill(); }
                            catch { }
                        }
                    }
                    try
                    {
                        executorProcess.CancelOutputRead();
                        executorProcess.CancelErrorRead();
                    }
                    catch { }
}


        void executorProcess_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
          Console.WriteLine(e.Data);
        }

       private void executorProcess_DataReceived(object sender,
            DataReceivedEventArgs e)
        {
            Console.WriteLine(e.Data);
        }

推荐答案

如果您使用的是c#,那将更好,就像Sergey所说的那样,在您自己的应用程序中完成所有工作,而不是在另一个应用程序中完成处理,尤其是如果您要获取错误消息等时.

请尝试以下操作: http://stackoverflow.com/questions/2250297/how-to-run-a-sql-script-using-c-sharp [
If you are using c# then it would be much better like Sergey said to do all your work in your own application instead of out in another process especially if you want to get the error messages etc.

Try the following : http://stackoverflow.com/questions/2250297/how-to-run-a-sql-script-using-c-sharp[^]


请参阅我对Mehdi回答的最后评论.在讨论了您为什么需要一个单独的流程以及为什么真正需要它的原因之后,让我们看看您如何执行它.

我可以看到的最大问题是,您在两个地方完全阻止了异常的传播.你绝对不应该这样做;相反,您应该只在每个线程的堆栈顶部执行一次.而且,您绝不应该采取任何行动就将异常置于首位.您应该获取并收集异常信息.如果这是UI,则可以将异常通知UI线程.我通常使用线程包装器类中声明的事件来执行此操作,甚至在UI线程中也要处理此问题(使用UI线程调用机制).在其他情况下(现在您仅使用控制台,但是需要为该代码的其他用途做准备),您需要写出异常信息和/或将其记录下来,例如使用System.Information.EventLog.

您需要更改此代码,并查看异常情况.

线程的终止也很成问题.你为什么会杀死这个过程?这是不安全的.您是否尝试过自己的代码? -这种杀人案有没有发生过?我永远不会做;我将等待该过程,直到它永远合法终止.它不应该花费无限的时间.

又为什么您要无条件取消错误/输出?如果进程本身退出,则永远不需要.

请对其进行分析并提供一些反馈.

—SA
Please see my last comment to the answer by Mehdi. After we discussed why you need a separate process and I can see why you really might need it, let''s see how you do it.

The biggest problem I can see is that you totally block the propagation of exceptions, in two places. You should never do it; instead, you should do it only once, on the very top of stack of every thread. And you should never leave the exception caught on top without any action. You should get exception information and collect it. If this is the UI, you can notify the UI thread on the exceptions. I usually do it using an event declared in a thread wrapper class and handle this even in the UI thread (using UI thread invocation mechanism). In other cases (now you just use the console, but you need to make provisions for other uses of this code), you need to write out exception information and/or log it, for example using System.Information.EventLog.

You need to change this code and see what happens with exceptions.

The termination of the thread is also very questionable. Why would you ever kill the process? This is unsafe. Did you experiment with your code? — does this kill case ever happen? I would never do it; and I would wait for the process until it legitimately terminate itself forever. It should not take infinite time.

And why do you cancel error/output read unconditionally? If the process exit by itself, it is never needed.

Please analyze it and provide some feedback.

—SA


这篇关于System.Diagnostic.Process的线程池问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆