很多朋友对于net 6中创建进程Process.Start时设置UseShellExecute对性能的影响和不太懂,今天就由小编来为大家分享,希望可以帮助到大家,下面一起来看看吧!
在开始之前,我们先回顾一下UseShellExecute 属性的作用。在Process.Start中,允许调用Shell来打开进程。输入不一定是exe等可执行文件,也可以是txt文件等文件。当传入一个文件时,系统会使用该文件的默认打开程序,按照默认的打开程序打开该文件。例如,默认情况下将使用记事本程序打开txt文件。要实现此效果,需要将UseShellExecute 设置为true 值
如果设置为true,则会在dotnet底层调用win32的ShellExecuteExW函数。
对于打开一个exe,很多时候,除非需要添加动词等,否则不需要使用ShellExecuteExW来启动。也就是说,如果你清楚地知道自己正在启动一个进程,只需要在启动时传递参数,而没有其他要求,那么你可以放心地将UseShellExecute设置为false。当然, false 也是默认值。
为什么将UseShellExecute 设置为真正的性能不佳?这还需要从dotnet的调用ShellExecuteExW函数方法说起。
在dotnet的Process.Start方法中,有很多重载方法,最终都会转移到public bool Start()方法中。在这个方法中,会进入平台相关的StartCore方法。
这里我们只讨论Windows下StartCore方法的实现。它的实现是基于Windows下创建进程使用的CreateProcessW和ShellExecuteExW函数的区别。因此,需要判断UseShellExecute属性来决定调用哪个方法。
public parts class Process : IDisposable { . //忽略其他代码private bool StartCore(ProcessStartInfo startInfo) { return startInfo.UseShellExecute ? StartWithCreateProcess(startInfo); } . //忽略其他代码} 先来看看StartWithCreateProcess方法。这种方法比较简单。省略的代码如下
publicpartial class Process : IDisposable { . //忽略其他代码private unsafe bool StartWithCreateProcess(ProcessStartInfo startInfo) { if (startInfo.UserName.Length !=0) { . //忽略其他代码retVal=Interop.Advapi32. CreateProcessWithLogonW( startInfo.UserName, startInfo.Domain, (passwordPtr !=IntPtr.Zero) ?passwordPtr : (IntPtr)passwordInClearTextPtr, logonFlags, null, //我们不需要这个,因为所有信息都在命令行中commandLinePtr,creationFlags, ( IntPtr)environmentBlockPtr,workingDirectory, refstartupInfo, //指向STARTUPINFO 的指针ref processInfo //指向PROCESS_INFORMATION 的指针); } else { . //忽略其他代码retVal=Interop.Kernel32.CreateProcess( null, //我们不需要这个,因为所有信息都在命令行中commandLinePtr, //指向命令行字符串的指针refused_SecAttrs,//处理安全属性的地址,我们不需要继承句柄refused_SecAttrs, //线程安全属性的地址true, //句柄继承标志CreationFlags, //创建标志(IntPtr)environmentBlockPtr, //指向new 的指针。环境块工作目录,//指向当前目录名称的指针refstartupInfo,//指向STARTUPINFO的指针refprocessInfo//指向PROCESS_INFORMATION的指针); } . //忽略其他代码} . //忽略其他代码} 在dotnet代码中,可以看到StartWithCreateProcess方法需要很多代码,但实际上只是调用了win32方法,这个方法比较多麻烦。
接下来我们看一下StartWithShellExecuteEx方法的实现。通过该方法的实现,可以知道为什么在Windows下,设置UseShellExecute为true,当调用线程不是STA时,性能会很差。
publicpartial class Process : IDisposable { . //忽略其他代码private unsafe bool StartWithShellExecuteEx(ProcessStartInfo startInfo) { . //忽略其他代码ShellExecuteHelperexecuteHelper=new ShellExecuteHelper(shellExecuteInfo); if (!executeHelper.ShellExecuteOnSTAThread()) { . //忽略其他代码} . //忽略其他代码} . //忽略其他代码} 可以看到StartWithShellExecuteEx中使用了ShellExecuteHelper辅助方法来实施它。也可以通过ShellExecuteOnSTAThread来猜测。这是在STA 线程上执行的。这是因为如果使用启动线程来调用文件打开,有些COM需要STA线程。但是,如果当前线程不是STA的线程,应该如何执行呢?
接下来继续看ShellExecuteOnSTAThread的实现
Internal unsafe class ShellExecuteHelper { . //忽略其他代码public bool ShellExecuteOnSTAThread() { //ShellExecute() 需要STA 才能正常工作。 if (Thread.CurrentThread.GetApartmentState() !=ApartmentState.STA) { ThreadStart threadStart=new ThreadStart(ShellExecuteFunction); }线程执行Thread=new Thread(threadStart) { IsBackground=true, Name=’.NET Process STA’ }; executionThread.SetApartmentState(ApartmentState.STA);执行线程.Start();执行线程.Join() ; } else { ShellExecuteFunction(); } . //忽略其他代码return _succeeded; } private void ShellExecuteFunction() { try { if (!(_succeeded=Interop.Shell32.ShellExecuteExW(_executeInfo))) ErrorCode=Marshal.GetLastWin32Error (); } catch (EntryPointNotFoundException) { _notpresent=true; } } . //忽略其他代码} 可以看到在dotnet中,判断当前线程。如果不是STA线程,则启动另一个STA线程来执行代码,并等待启动的STA线程执行完成后再同步等待另一个线程。这就是性能比较差的原因。性能较差需要启动线程并等待线程执行完成。
原创文章,作者:小su,如若转载,请注明出处:https://www.sudun.com/ask/112566.html
用户评论
来瓶年的冰泉
看到这个标题就忍不住想说一句,NET Core 的进程管理真是一门大学问!以前确实不知道 Process.Start() 这个方法还有参数可以用 ShellExecute 来控制,现在看来学习成本还挺高啊。希望这篇文章能详细解释一下为什么要用 UseShellExecute 和其带来的性能影响。
有19位网友表示赞同!
今非昔比'
我一直觉得网络编程效率才是王道,如果这个 UseShellExecute 真的会对性能造成很大影响,那还是直接用 .NET 自带的方法来创建进程吧,省得太麻烦了。不过看标题应该是比较深入的分析了,我还是看看文章内容再说。
有11位网友表示赞同!
凝残月
我目前在开发一个多线程应用程序,涉及到频繁地创建和销毁进程。性能问题一直是我的心头痛,看到这篇文章感觉很有用啊!希望作者能给出具体的测试数据,方便我们参考和选择合适的方案。
有7位网友表示赞同!
念安я
NET 6 中对进程管理的改进确实不少,之前用过 Process.Start() 创建进程的感觉就是很耗资源,每次操作都像慢動作一般。现在看来 UseShellExecute 是值得尝试的改进方向,尤其是在需要频繁创建进程的时候。
有8位网友表示赞同!
半梦半醒半疯癫
我刚学习 C# 不伦是开发,没怎么接触过进程管理这些高级内容。这篇文章标题听起来就很复杂了,我还是乖乖地先把基本的 C# 语法学下去再说吧!
有12位网友表示赞同!
♂你那刺眼的温柔
作为一名资深程序员,使用 UseShellExecute 创建进程这种方案倒不算新颖,很多年前就已经被大家提出来了。关键在于该方案的优缺点分析,以及在 NET 6 中如何更有效地应用。期待作者给出一些具体案例和应用场景。
有7位网友表示赞同!
坠入深海i
我曾经做过一个跨平台的项目,使用 Process.Start() 创建进程的时候总是遇到各种各样的问题,跨平台的兼容性实在是太差了!不知道这个 UseShellExecute 在多平台上表现怎么样?希望这篇文章能给我一些启发。
有12位网友表示赞同!
落花忆梦
最近在研究 NET 6 的性能优化,没想到进程管理居然是个重要的一部分。感觉自己还有很多知识需要学习,看来要花更多的时间阅读技术文档和博客文章了,尤其是像这样的深入分析文章!
有11位网友表示赞同!
拽年很骚
我更看重开发效率,如果 UseShellExecute 真能提高创建进程的速度,那对于大型项目的开发来说确实是一个不错的选择。不过还得考虑实际项目中不同的场景,是否真的能够带来显著的性能提升。
有13位网友表示赞同!
怪咖
学习技术真是一件不断累积的过程,从简单的代码到复杂的应用程序设计,总需要不断地探索和改进。看到这篇文章标题,我深感自身的不足,决定认真研究一下 NET 6 的进程管理机制和 UseShellExecute 参数的使用方法。
有17位网友表示赞同!
败类
在很多情况下,UseShellExecute并不会带来明显的性能提升,除非你的应用特别依赖于系统 shell 的功能。对于大部分场景来说,直接使用 .NET 提供的编程接口来创建进程更加简洁高效。
有7位网友表示赞同!
掉眼泪
以前我总是习惯用 Process.Start() 来创建进程,现在看来还有很多更优选的方法可以使用。感谢作者分享这篇文章,让我有了学习的机会!
有15位网友表示赞同!
素婉纤尘
对于大型、复杂的多线程应用而言,性能优化是非常关键的一步,而进程管理也是其中重要的一部分。期待作者能够详细探讨 UseShellExecute 与其他进程创建方法在实际项目中的应用场景和对比分析。
有15位网友表示赞同!
娇眉恨
NET 6 的升级迭代真是非常令人期待!希望能多看到一些像这样实用的文章,帮助我们更好地理解和掌握新的技术内容。
有19位网友表示赞同!
╭摇划花蜜的午后
从标题中可以看出这篇文章很有深度,不仅探讨了 UseShellExecute 带来的性能影响,还可能涉及到更深层次的进程管理机制分析。我很赞赏作者对 NET 6 的深入研究和分享!
有11位网友表示赞同!
素衣青丝
NET 6 真是一门非常全面的技术平台,学习起来真的需要花费不少时间和精力。希望我能像这篇文章作者一样,能够将自己的技术经验总结出来,帮助更多的人了解和掌握 NET 6。
有15位网友表示赞同!
断秋风
性能优化真是个永恒的话题啊!使用合适的工具和方法才能提升代码效率,避免出现资源浪费的情况。期待文章能给到一些具体的解决方案,让我们能够更好地应用 UseShellExecute 创建进程!
有19位网友表示赞同!
野兽之美
作为一名初学者,我对于 NET 6 的大部分功能还不太熟悉,希望这篇文章能帮我更全面地理解进程管理的原理和实践方法,以便在未来的开发中做出更加明智的选择。
有14位网友表示赞同!