如何解决C#调用cmd命令行执行exe程序,并发时失败率很高问题?

smile2021 2019-04-12 10:11:31
场景:前端请求后端接口,并发送一段c语言代码,由后端调用命令行执行gcc编译,然后再调编译后生成的exe程序读出exe程序的输出结果,接口把这个结果返回给前端页面。

问题:在队列阻塞情况下执行一次一条没问题,都能得到正确结果,但是并发请求时就会出现部分请求失败,无法返回结果问题。

备注:代码设置了cmd命令行超时关闭并杀死进程。
积分不多,请大家多多包涵


代码:

public async static Task<CompilerData> RunCmd(CompilerData cdata)
{
await Task.Run(() =>
{
var cancellationTokenSource = new CancellationTokenSource();
var th = new Thread(() =>
{
Run(cdata);
});
cancellationTokenSource.Token.Register(() =>
{
th.Abort();
cdata.TimeOut = true;
Process[] process = Process.GetProcesses();
var proc = process.FirstOrDefault(i => i.ProcessName == cdata.ExeName);
if (proc != null)
{
if (!proc.HasExited)
{
//立即停止相关进程。意即,进程没回应,强制关闭
proc.Kill();
}
if (proc != null)
{
proc.Close();
proc.Dispose();
proc = null;
}
}
});
cancellationTokenSource.CancelAfter(60000);
th.Start();
th.Join();

});
return cdata;
}

/// <summary>
/// 执行命令
/// </summary>
/// <param name="cdata"></param>
private static void Run(CompilerData cdata)
{
List<ProcessModel> proclist = HelperCache.GetCache("Process") as List<ProcessModel>;
if (proclist == null)
{
proclist = new List<ProcessModel>();
}
cdata.IsSuccess = false;
cdata.Error = "命令为空";
if (!string.IsNullOrWhiteSpace(cdata.ExecuteThis))
{
Process proc = new Process();//创建进程对象
proc.StartInfo.FileName = CMDPath;//设定需要执行的命令
proc.StartInfo.Arguments = "/C " + cdata.Executor + " " + cdata.ExecuteThis;//“/C”表示执行完命令后马上退出
proc.StartInfo.UseShellExecute = false;//不使用系统外壳程序启动
proc.StartInfo.RedirectStandardInput = false;//不重定向输入
proc.StartInfo.RedirectStandardOutput = true; //重定向输出
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.CreateNoWindow = true;//不创建窗口
try
{
if (proc.Start())
{

Stopwatch watch = new Stopwatch();
watch.Start();
ProcessModel model = new ProcessModel()
{
Id = proc.Id,
ProcessName = proc.ProcessName,
StartTime = proc.StartTime,
MaxCompileTime = cdata.MaxCompileTime
};
proclist.Add(model);
HelperCache.SetCache("Process", proclist);
HelperCache.RemoveAllCache(cdata.ExeName);
HelperCache.SetCache(cdata.ExeName, cdata.ExeName);
cdata.Success = proc.StandardOutput.ReadToEnd();//读取进程的输出
cdata.Error = proc.StandardError.ReadToEnd();
watch.Stop();
proc.WaitForExit();
cdata.CompileTimeMs = watch.Elapsed.TotalMilliseconds;
OnlineData.Helper.HelperLog.Info(string.Format("成功{0},失败{1}", cdata.Success, cdata.Error));
cdata.IsSuccess = string.IsNullOrWhiteSpace(cdata.Error) ? true : false;
}
}
catch (Exception ex)
{
cdata.Error = proc.StandardError.ReadToEnd();
OnlineData.Helper.HelperLog.Info(string.Format("成功{0},失败{1}", cdata.Success, cdata.Error), ex);
cdata.IsSuccess = false;
}
finally
{
if (!proc.HasExited)
{
//立即停止相关进程。意即,进程没回应,强制关闭
proc.Kill();
}
if (proc != null)
{
proc.Close();
proc.Dispose();
proc = null;
}
}
}
}
...全文
515 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
smile2021 2019-04-12
  • 打赏
  • 举报
回复
引用 4 楼 以专业开发人员为伍 的回复:
用 Task 你还用什么 Thread?
另外问一下大神,在Task.Run中用thread会有什么结果?因为这个外部是一个异步的方法,调用这个RunCmd,所以需要有await,用thread无法使用await,那么在外部的方法中就要再写一个Task.Run来包裹RunCmd了,这样的话和在RunCmd里面使用Task.Run岂不是一样了?
smile2021 2019-04-12
  • 打赏
  • 举报
回复
引用 8 楼 正怒月神 的回复:
是不是由于执行的是同一个exe, 第一个还没完成,第二个要生成exe时,就出问题了
生成exe没问题,就是返回结果有些超时严重
smile2021 2019-04-12
  • 打赏
  • 举报
回复
引用 7 楼 以专业开发人员为伍 的回复:
打个比方把,假设每一个人都是不与别人合作的、细节上不肯做出重构的、不异步让出资源的,那么这样的人你给“并发10个”就肯定比顺序工作还慢10倍以上。这是正常的。而你还要动不动“杀掉”他们吗?
您好,首先不能死等,因为如果前端传过来一个死循环的代码,后端编译执行岂不是死在这里了,所以要超时杀死他们。其次,因为水平问题,用task我不会设置超时终止进程,所以用了Thread。这里调用的等于是第三方程序了无法再其内部设置终止判断。最后这里每次前端传过来的代码都会不同,因为这是考试题,同一道编程题,会有不同的写法,所以后端编译的也是唯一的一个exe程序。在这个情况下,如果在100人的考场,假设一个极端的情景:同一时刻50个请求过来就会有部分请求失败的情况出现。
正怒月神 2019-04-12
  • 打赏
  • 举报
回复
是不是由于执行的是同一个exe, 第一个还没完成,第二个要生成exe时,就出问题了
  • 打赏
  • 举报
回复
打个比方把,假设每一个人都是不与别人合作的、细节上不肯做出重构的、不异步让出资源的,那么这样的人你给“并发10个”就肯定比顺序工作还慢10倍以上。这是正常的。而你还要动不动“杀掉”他们吗?
  • 打赏
  • 举报
回复
另外有谁说过多线程就会加快运行速度?多线程操作都是以减慢单个任务运行速度为代价的,更何况你的单个任务都是独占和“死等”进程。所以你这里的“杀死进程”看起来太激进了,而且你要求的仅仅在皮毛上把独占的进程给“高并发”的想法也太想当然了。
smile2021 2019-04-12
  • 打赏
  • 举报
回复
引用 3 楼 stherix 的回复:
是你的HelperCache的问题吗,可能不是线程安全的? 理论上起很多控制台窗口运行gcc是不会有问题 你可以试下2任务并行,看一下是不是cpu负担重从而导致任务超时
HelperCache只是用来记录一下缓存,在另一个地方循环读取出记录杀死进程,防止一些假死进程占用资源。 另外我看生成的文件目录中的的文件都正常,请求多少100次生成100个文件,而且文件都没有出错。 5个任务同时执行不会出错,都正常返回。 我不知道是不是我用的工具有响应时间设置,一旦响应时间超时就认为失败? 我用的 http://coolaf.com/tool/testing 这个工具本地化测试的。 1000次请求队列访问是不会出问题的,调用cmd是需要时间的,同时都过来调用cpu在负载过重情况下会阻塞其他请求,是不?
  • 打赏
  • 举报
回复
用 Task 你还用什么 Thread?
stherix 2019-04-12
  • 打赏
  • 举报
回复
是你的HelperCache的问题吗,可能不是线程安全的? 理论上起很多控制台窗口运行gcc是不会有问题 你可以试下2任务并行,看一下是不是cpu负担重从而导致任务超时
smile2021 2019-04-12
  • 打赏
  • 举报
回复
大神何在,速速前来
smile2021 2019-04-12
  • 打赏
  • 举报
回复
自己顶起来,大神快来看

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧