二进制管道, PowerShell 竟还不如 CMD

2021-01-26 21:10:04 +08:00
 orannge

这几天用了下 PowerShell,发现用到二进制管道的地方速度奇慢,例如tar -cf - 1.bin > 1.tgz。测试文件 100M,CMD 敲下命令就出结果了,PowerShell 用了整整三十来秒!就算执行结束了,结果也还是错的。

类似命令还有cat 1.bin > 2.bin,进一步了解之后发现catGet-Content的别名,会以字符串读取文件,> 也不是重定向流,仅仅是 | Out-File 的语法糖。找了一圈,设置编码等等,发现官方并没有等效命令,GitHub 16 年的 issue 现在都没关(PowerShell#1908)?

有个第三方模块说可以解决这个问题,Use-RawPipeline,好的装上,于是命令变成run tar "-cf" "-" 1.bin | out2 1.tgz,虽然不那么直观,参数引号不能忘,速度差了一倍,好歹是能用了。然后这模块加载要 700ms,终端打开都要卡一下,于是设置function load { Import-Module -Name Use-RawPipeline },用到相关命令的时候手动 load 一下。啊这,cmd /c tar -cf - 1.bin > 1.tgz不香吗?

测试用的内存盘,综合下来 WSL2 满速 900M/S,CMD 满速 700M/S,PowerShell 7.1 只有 40M/S,Use-RawPipeline 速度 320M/S 。PowerShell 15-20 倍速度损失,Use-RawPipeline 1 倍速度损失。二进制管道用到的地方还是挺多的,tar/git/curl 等等。

选择 PowerShell 是因为想在 Windows 下用用脚本,毕竟 CMD 实在太难用了。有说 PowerShell 已经跨平台,比 bash 都好用,结果连 CMD 都完全替代不了,哈哈。

5067 次点击
所在节点    Windows
36 条回复
Jirajine
2021-01-26 21:16:32 +08:00
慢可能是因为二进制数据先被解析成 string 了,并且对无效字符可能进行替换。你会发现最终产生出来的文件已经面目全非。
nightwitch
2021-01-26 21:29:51 +08:00
裸 powershell 冷启动也要几百毫秒
稍微加点 oh-my-posh 再加点其他模块,冷启动时间慢到不能忍受.
leido
2021-01-26 21:32:08 +08:00
powershell 的管道不是原始字节流 , 包装成 .net 对象 的
codehz
2021-01-26 21:34:17 +08:00
其实说到底就是 windows 的坑,0202 年还在折腾编码问题,以至于不能 utf-8 走天下。。。如果假设所有终端程序都用 utf-8,就不会做出先解析输出内容的设计决策。。。
leido
2021-01-26 21:36:07 +08:00
AndyAO
2021-01-26 21:37:49 +08:00
Out-File 处理的本来就是字符串,不是二进制数据,这个在文档上有,所以只要看过文档就应该立即能明白.

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/out-file?view=powershell-7.1

没有什么东西是完美的,这是 PowerShell 取舍,他认为这么做在大多数情况下效率都会更高.

如果你认为 PowerShell 这个判断是错误的,可以用其他方式来实现.例如,你可以直接在 PowerShell 中调用 CMD 命令.

学习使用 PowerShell,最好是以 PowerShell 的思维来思考,而不是要求 PowerShell 迁就你之前的习惯.
by73
2021-01-26 21:47:32 +08:00
跟 pwsh 的设计有点关系,pwsh 管道传递的是 object,基本所有操作都是基于 object 和字符串的,某些情况下用着会比较舒服(例如获取一些信息,可以直接用 select,不需要写正则去 grep 等),而且 pwsh 最大的一个特性是跟 csharp 的代码结合的很好,虽然我不怎么用 = =

P.S. 我也要吐槽以下 pwsh,重定向总喜欢给我输出 UTF16 。。
AndyAO
2021-01-26 21:48:42 +08:00
tar/git/curl 这些东西,都是类 Unix 平台上的工具,可以说是量身打造的.

在 PowerShell 上来使用它们,效率不如原来的平台上高几乎是必然的.

作为后来者这个很吃亏,如果有人在 C#上写了完全兼容 Git 的工具,那么效率就会很高,其他工具也是如此.
orannge
2021-01-26 21:57:12 +08:00
@AndyAO 这么说都是生态问题,类似这种命令本就是留给 CMD 来处理的
AndyAO
2021-01-26 22:18:24 +08:00
@orannge #9
1. 是否是生态的问题

在第 8 楼上,我的意思是这样的,如果有类似的工具是用 C#写的,那么用 Unix 上的的使用方式反而是蹩脚的.

之所以感觉很蹩脚很不好用,是因为你在跨平台使用这些工具,例如 git,在 Windows 跑起来就需要很多支持工具,有兼容性问题是难免的.

我不确定 C#上是否已经有很好的工具能满足你那个操作需求,如果能的话,那么你可以更改自己的习惯,如果没有这样的好工具,那就是生态问题.

这个生态问题可能会很长时间都解决不了,因为新的工具要想替代老的,除非好很多,否则的话一般是不会替代的,会将就着用,很长很长时间.

2. 是不是本来就留给 CMD 处理的

坦白讲,我也不清楚他们团队的想法,但让我想到了此前遇到的问题,那就是建立软硬链接,必须要调 CMD,否则就要用 Win32Api.

你现在去 StackOverFlow 还能看到这样的问题,那些被标记为√的,都是这个方案.

但是在 PowerShell V5 后就内置了,为 New-Item 增加了新的参数,支持所有链接.

也许谁都想做尽善尽美的东西,能力有限,还是要分个轻重缓急的吧.
favourstreet
2021-01-26 22:26:58 +08:00
所以我在 powershell 里常用的一个命令是 cmd.exe /c "……"
rekulas
2021-01-26 22:31:52 +08:00
win 平台一直用 gitscm 基本没遇到什么问题 而且跟 linux 工具包一致 通畅
Tumblr
2021-01-26 23:00:13 +08:00
感觉就是敲了几个命令就来妄加评判的无知之谈。。。
通篇在说读写速率的问题,没看到哪条佐证楼主观点,甚至楼主都貌似不知道 PowerShell 的管道传输的是对象。。。

力气不够怪刀重,功夫不精怨招轻。。。
iamwho
2021-01-26 23:03:46 +08:00
UnknownSky
2021-01-26 23:24:48 +08:00
emm,关闭 WD 试试,日常遇到 Powershell 命令慢的要死,把 Windows Defender 关了就好了
ETiV
2021-01-26 23:32:53 +08:00
LZ 会写 bash 脚本的话,可以装个 Cygwin 工具集合
我既不会 Power Shell 又不想写 bat
在 Windows 上基本都是用的 Cygwin+bash 了
lxilu
2021-01-27 00:18:04 +08:00
@codehz 这应是设计为`了对象管道
bthulu
2021-01-27 08:53:46 +08:00
@AndyAO 诺基亚也是这样想的, 绝不能迁就用户的习惯
AndyAO
2021-01-27 09:06:26 +08:00
@bthulu #16 苹果和特斯拉也是
AndyAO
2021-01-27 10:19:14 +08:00
看到前面很多人提到了 PowerShell 模块加载的速度问题.
其实模块没有必要提前进行加载,除非直接对全局进行了更改,比如说 posh-git.
在 PowerShell 中,只要你的模块是安装在指定目录中的,可以在首次使用的时候自动加载.
很多人可能不清楚这点,所以就把很多的模块在最初全部导入了,那速度肯定快不了.
不过,如果这些模块确定要使用,那么提前导入还是有好处的,加快了使用时候的速度和提高了一致性.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/748686

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX