返回列表 发帖

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

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

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

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

评分人数

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

TOP

回复 2# 523066680

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

TOP

回复 3# xczxczxcz


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

评分人数

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

TOP

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

效率比楼主的初始化字符数组稍高一些
$start=[System.DateTime]::Now
$num=0
$array=(65..90) + (97..122) + (48..57)
while ($num -lt 10000){
[char[]](Get-Random -Count 7 -InputObject $array) -join ""
$num+=1
}
([System.DateTime]::Now - $start).TotalSeconds
pauseCOPY
输出结果到控制台,最占时间,面向对象资源开销也比较大,所以面向过程的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

评分人数

[url=][/url]

TOP

100W, 输出到文件. 1.9s (包括 1.3s 的启动及编译时间
#!/usr/bin/pwsh -nop
$Source = @"
using System.IO;
using System.Linq;
using System;
namespace Foo
{
    public static class Bar
    {
        private static Random random = new Random();
        
        public static void RandomString()
        {
            const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
            using (var file = new StreamWriter("test.txt")) {
                for (int i = 0; i <= 1000000; i++) {
                    file.WriteLine(new string(Enumerable.Range(1, 7).Select(n => chars[random.Next(n == 1 ? 26 : chars.Length)]).ToArray()));
                }
            }
        }
    }
}
"@
Add-Type -TypeDefinition $Source -Language CSharp
[Foo.Bar]::RandomString();COPY
应该也算 PowerShell 吧 (笑
2

评分人数

TOP

回复 7# bailong360

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

TOP

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

因为……
They can't see sharp.
[url=][/url]

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 大佬们寻求优化方案......
use rand::{seq::SliceRandom, FromEntropy};
use rand_xorshift::XorShiftRng;
use std::fs::File;
use std::io::Write;
fn main() {
    let chars = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    let mut rng = XorShiftRng::from_entropy();
    let mut file = File::create("test.txt").unwrap();
    for _ in 0..1000000 {
        let v = (0..7)
            .map(|n| {
                if n == 0 {
                    *chars.choose(&mut rng).unwrap()
                } else {
                    **(&chars[0..26].choose(&mut rng).unwrap())
                }
            })
            .collect::<Vec<_>>();
        file.write_all(&v).unwrap();
        file.write_all(&[b'\n']).unwrap();
    }
}COPY
=== 更新 ===
艹, 应该用 BufWriter wrap 一下, 这样就 0.16s 左右了...
let file = File::create("test.txt").unwrap();
let mut file = BufWriter::new(file);COPY
1

评分人数

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

TOP

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

如果非常在意几秒的差异,这样也许会比 get-Random 快那么一点。
$t=get-date
$chr = 'QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890';
$swr = New-Object IO.StreamWriter('E:\1.Log', $false, [Text.Encoding]::ASCII);
$rnd = New-Object System.Random;
$arr = [Array]::CreateInstance('char', 7);
for ($i = 0; $i -lt 1000000; $i++) {
    $arr[0] = $chr[$rnd.Next(26)];
    for ($j = 1; $j -le 6; $j++) {
        $arr[$j] = $chr[$rnd.Next(62)];
    }
    $swr.WriteLine($arr);
}
$swr.Close();
((get-Date) - $t).TotalSecondsCOPY
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

来水一发,汇编
Include masm32rt.inc
.const
Table DB 'ACBDFEGHIKJLMOPQNRSTUVWXYZadcbefhigjklnmpoqsrtuvwzyx6578902314'
.data?
Input db 5 dup (?)
Num dd ?
Align 10h
Buffer db 9*10000+1 dup (?)
.code
Start:
Invoke ArgClC,1,Offset Input
Sub esp,4
Invoke atodw_ex,Offset Input
Mov Num,Eax
Add Esp,4
Lea Esi,Table
Mov Ecx,Eax
.Repeat
Push Ecx
Lea Edi,Buffer
Mov Ecx,10000
Align 10h
.Repeat
Push Ecx
Invoke nrandom,26
Lea Eax,[Eax+65]
StoSB
Mov Ecx,6
Align 4h
.Repeat
Push Ecx
Invoke nrandom,SizeOf Table
Mov Al,[Eax+Esi]
StoSB
Pop Ecx
.UntilCxZ
Mov Ax,0A0DH
Mov Word Ptr [Edi],Ax
Inc Edi
Inc Edi
Pop Ecx
.UntilCxZ
Xor Eax,Eax
StoSB
Invoke StdOut,Offset Buffer
Pop Ecx
.UntilCxZ
Invoke ExitProcess,NULL
End StartCOPY
I3 CPU+机械
100w个,输出到控制台,40s(真感人)
输出到txt,220ms
直接>nul,180ms
test 要生成的数目/1w
生成100w:test 100

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

评分人数

TOP

返回列表