[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[技术讨论] PowerShell解决用纯BAT几秒内生成几万个字符串组的问题

N久以前的事了。用纯P写,总是没达到要求。[任意7位数,以大定字母开头,后6位为大小写字母和数字的任意组合]
现在用 Powershell 写。不开多任务,约3秒多点 完成10000次,7秒多点 20000次 10秒30000次,也算符合要求。
如何把开头的字符数组直接写,不用 toCharArray()分割.可以少约 1秒。
  1. $time=get-date
  2. $ULetter=@('ABCDEFGHIJKLMNOPQRSTUVWXYZ'.toCharArray())
  3. $DigitLetter=@('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'.toCharArray())
  4. while ($num -lt 10000){
  5. [Collections.ArrayList]$random=@(get-random -input $ULetter) #大写字母开头
  6. $random+=get-random -input $DigitLetter -count 6 #数字和大小写字母
  7. $str=-join $random  #用 + 的方法连接字符约少 0.2秒。
  8. #if($str -match '(\d+){1,}') { #至少包含一位数字
  9. $str
  10. $num++
  11. #}
  12. }
  13. ([datetime]::now - $time).TotalMilliSeconds
  14. pause
复制代码

本帖最后由 523066680 于 2019-3-21 19:28 编辑
  1. use Time::HiRes qw/time/;
  2. STDOUT->autoflush(1);
  3. my $ta = time();
  4. my @upper = ('A'..'Z');
  5. my @eles = ('a'..'z', 'A'..'Z', '0'..'9');
  6. my $e_len = scalar(@eles);
  7. my $key;
  8. for my $i (1..1000000)
  9. {
  10.    $key = $upper[rand(26)] . join("", map { $eles[rand($e_len)] } (1..6) ) ;
  11.    printf "%s\n", $key;
  12. }
  13. printf STDERR "time usage %.2f", time()-$ta;
复制代码
genCode.pl >F:/temp/a.txt
输出到机械硬盘,100W个,4秒

join "", map {} () 改成末尾append形式,100W个,3秒
  1. for my $i (1..1000000)
  2. {
  3.    $key = $upper[rand(26)];
  4.    grep { $key .= $eles[rand($e_len)] } (1..6);
  5.    printf "%s\n", $key;
  6. }
复制代码
CPU 频率 4GHz
1

评分人数

    • xczxczxcz: 历害,我的写法还要改进,多线程1000000个要 ...技术 + 1

TOP

回复 2# 523066680

I5  多线程 1000000个,要40多秒。感觉写法不太好。再研究一下。那个[random]等还用不好。

TOP

回复 3# xczxczxcz


    这种要求用解释型语言太伤了,根本没有效率可言
1

评分人数

    • xczxczxcz: 本论坛经常打不开,说的是。技术 + 1

TOP

本帖最后由 ivor 于 2019-3-22 07:52 编辑

效率比楼主的初始化字符数组稍高一些
  1. $start=[System.DateTime]::Now
  2. $num=0
  3. $array=(65..90) + (97..122) + (48..57)
  4. while ($num -lt 10000){
  5. [char[]](Get-Random -Count 7 -InputObject $array) -join ""
  6. $num+=1
  7. }
  8. ([System.DateTime]::Now - $start).TotalSeconds
  9. pause
复制代码
输出结果到控制台,最占时间,面向对象资源开销也比较大,所以面向过程的c语言最有优势。
1

评分人数

    • xczxczxcz: 我开始也这样弄过,更慢。大写字母开头技术 + 1
#&cls&@powershell "Invoke-Expression ([Io.File]::ReadAllText('%~0',[Text.Encoding]::UTF8))" &pause&exit

TOP

回复 3# xczxczxcz
我们的代码实质是差不多的,是解释器的优化不同。

回复 4# 老刘1号
如果解释器有对这类操作优化,内部实现对应的功能模型,执行速度就会接近编译型语言。
举个例子,CLGO 绘图,
基于CLGO的COOL解释器
对于图形程序,如果大部分指令调用都在解释层挨个执行,不要说GPU,CPU也是无法充分利用的。
OpenGL是怎么实现快速渲染的呢?DrawArrayElemensts 函数,我告诉GPU,我要三角形,把包含数十万个三角形坐标的数组指针传递过去,
然后把转换平移等通用的操作通过矩阵数组传递,GPU就会并行处理这些三角形的光栅化操作(空间变换、投影、深度测试、像素化、抗锯齿等),每秒是数十甚至上百帧。
如果每一个三角形都调用一次而不是传指针,CPU是吃不消的。所以那个帖子我记得有个作品的动图,画的圈并不多(不过万),但却是卡顿的。

如果要对这些批次的三角形做特殊效果,水墨描边、素描风格等,可以使用着色语言(Shader Language),一套直接和GPU核打交道的指令。
这也是行业发展的结果,硬件厂商知道你会大量执行这些操作,所以直接提供更合适的接口。

当时我也没什么建议,这里面解释器的学问太多了,我不懂。另外全套操作下来会感觉,还是用现成的吧,连硬件厂家都帮你考虑好了。

说完掏出硬件属性看了一下,看来还得学,不然挂着这个显卡太浪费
5

评分人数

TOP

100W, 输出到文件. 1.9s (包括 1.3s 的启动及编译时间
  1. #!/usr/bin/pwsh -nop
  2. $Source = @"
  3. using System.IO;
  4. using System.Linq;
  5. using System;
  6. namespace Foo
  7. {
  8.     public static class Bar
  9.     {
  10.         private static Random random = new Random();
  11.         
  12.         public static void RandomString()
  13.         {
  14.             const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  15.             using (var file = new StreamWriter("test.txt")) {
  16.                 for (int i = 0; i <= 1000000; i++) {
  17.                     file.WriteLine(new string(Enumerable.Range(1, 7).Select(n => chars[random.Next(n == 1 ? 26 : chars.Length)]).ToArray()));
  18.                 }
  19.             }
  20.         }
  21.     }
  22. }
  23. "@
  24. Add-Type -TypeDefinition $Source -Language CSharp
  25. [Foo.Bar]::RandomString();
复制代码
应该也算 PowerShell 吧 (笑
2

评分人数

TOP

回复 7# bailong360

不会你的电脑比偶的还差吧。偶测试只有 0.716秒。

TOP

一个段子,
用Java的人都戴墨镜。

因为……
They can't see sharp.

TOP

回复 8# xczxczxcz


    看来还是我的最好,我居然只用了563MS
QQ 33892006

TOP

回复 8# xczxczxcz


    Linux 上 pwsh 比较慢
直接用 mono 编译运行的话, 就只要 0.56s 左右

TOP

本帖最后由 bailong360 于 2019-3-22 22:14 编辑

回复 7# bailong360


    这段 C# 好像太快了点...

我用 Rust 实现了一下, 然而也花了 3s. 目前正在向 Rust 大佬们寻求优化方案......
  1. use rand::{seq::SliceRandom, FromEntropy};
  2. use rand_xorshift::XorShiftRng;
  3. use std::fs::File;
  4. use std::io::Write;
  5. fn main() {
  6.     let chars = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  7.     let mut rng = XorShiftRng::from_entropy();
  8.     let mut file = File::create("test.txt").unwrap();
  9.     for _ in 0..1000000 {
  10.         let v = (0..7)
  11.             .map(|n| {
  12.                 if n == 0 {
  13.                     *chars.choose(&mut rng).unwrap()
  14.                 } else {
  15.                     **(&chars[0..26].choose(&mut rng).unwrap())
  16.                 }
  17.             })
  18.             .collect::<Vec<_>>();
  19.         file.write_all(&v).unwrap();
  20.         file.write_all(&[b'\n']).unwrap();
  21.     }
  22. }
复制代码
=== 更新 ===
艹, 应该用 BufWriter wrap 一下, 这样就 0.16s 左右了...
  1. let file = File::create("test.txt").unwrap();
  2. let mut file = BufWriter::new(file);
复制代码
1

评分人数

    • xczxczxcz: Rust 不会用,不知和C比哪个好?技术 + 1

TOP

本帖最后由 WHY 于 2019-3-25 23:05 编辑

如果非常在意几秒的差异,这样也许会比 get-Random 快那么一点。
  1. $t=get-date
  2. $chr = 'QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890';
  3. $swr = New-Object IO.StreamWriter('E:\1.Log', $false, [Text.Encoding]::ASCII);
  4. $rnd = New-Object System.Random;
  5. $arr = [Array]::CreateInstance('char', 7);
  6. for ($i = 0; $i -lt 1000000; $i++) {
  7.     $arr[0] = $chr[$rnd.Next(26)];
  8.     for ($j = 1; $j -le 6; $j++) {
  9.         $arr[$j] = $chr[$rnd.Next(62)];
  10.     }
  11.     $swr.WriteLine($arr);
  12. }
  13. $swr.Close();
  14. ((get-Date) - $t).TotalSeconds
复制代码
Microsoft Windows [版本 10.0.17763.379]
(c) 2018 Microsoft Corporation。保留所有权利。

C:\Users\WHY>PowerShell -exec ByPass "&'E:\Test\Test.PS1'"
1.8277292

C:\Users\WHY>
1

评分人数

    • xczxczxcz: 调用NET会快些,但比插入C#(NET)还是慢些。技术 + 1

TOP

回复 7# bailong360


    内嵌C#,秒啊

TOP

来水一发,汇编
  1. Include masm32rt.inc
  2. .const
  3. Table DB 'ACBDFEGHIKJLMOPQNRSTUVWXYZadcbefhigjklnmpoqsrtuvwzyx6578902314'
  4. .data?
  5. Input db 5 dup (?)
  6. Num dd ?
  7. Align 10h
  8. Buffer db 9*10000+1 dup (?)
  9. .code
  10. Start:
  11. Invoke ArgClC,1,Offset Input
  12. Sub esp,4
  13. Invoke atodw_ex,Offset Input
  14. Mov Num,Eax
  15. Add Esp,4
  16. Lea Esi,Table
  17. Mov Ecx,Eax
  18. .Repeat
  19. Push Ecx
  20. Lea Edi,Buffer
  21. Mov Ecx,10000
  22. Align 10h
  23. .Repeat
  24. Push Ecx
  25. Invoke nrandom,26
  26. Lea Eax,[Eax+65]
  27. StoSB
  28. Mov Ecx,6
  29. Align 4h
  30. .Repeat
  31. Push Ecx
  32. Invoke nrandom,SizeOf Table
  33. Mov Al,[Eax+Esi]
  34. StoSB
  35. Pop Ecx
  36. .UntilCxZ
  37. Mov Ax,0A0DH
  38. Mov Word Ptr [Edi],Ax
  39. Inc Edi
  40. Inc Edi
  41. Pop Ecx
  42. .UntilCxZ
  43. Xor Eax,Eax
  44. StoSB
  45. Invoke StdOut,Offset Buffer
  46. Pop Ecx
  47. .UntilCxZ
  48. Invoke ExitProcess,NULL
  49. End Start
复制代码
I3 CPU+机械
100w个,输出到控制台,40s(真感人)
输出到txt,220ms
直接>nul,180ms
test 要生成的数目/1w
生成100w:test 100

代码将指令、数据对齐到内存4整数倍地址,提高速度
随机数生成使用masmlib中的函数,不涉及api调用,浮点计算
由于懒得调api得时间做种子,目前种子固定。
5

评分人数

TOP

返回列表