我有一个bat文件
@echo %RANDOM%
并使用命令行
执行它start randomcheck.bat & start randomcheck.bat
打开两个控制台,两个控制台都包含相同的编号,4645。这不符合随机to provide different temp folders的目的(我只有在同时使用时才需要随机文件夹)。你如何批量生产普通随机发生器?
更新 https://stackoverflow.com/a/19697361/1083704量化了全球种子更新期。 Windows shell全局种子每秒更新一次。实际上,我必须再增加一秒的安全边际,以防止比赛,并希望这是足够的措施。这真的很糟糕。这意味着为我的iCore7启动8个进程将需要16秒。而且我仍然不确定这是否成功,因为没有正式指定,尽管最初有8个进程以相对时间偏移启动,但仍有可能发生两个进程同时完成,我必须注意它们是没有再次同时重启。这是完全废话,我的问题是这可以在批处理中解决,而不需要求助于C ++或VBScript吗?
答案 0 :(得分:8)
MC ND在他的答案中对所有计数100%正确,以及他的后续评论。
CMD.EXE的每个实例在启动时使用从1秒分辨率的当前时间派生的种子初始化随机数生成器。在同一秒内启动的所有CMD.EXE进程将获得相同的随机数序列。
另一个方面 - 连续秒的初始随机数变化非常缓慢。在我看来,初始随机数实际上可能是从时间推导出的种子值,但我不确定。
编辑 - 我最初通过实验推断了所有这些。但我已经看过confirmation from an authoritative source。
这是一个脚本,演示了CMD.EXE的种子每秒只更改一次,并且种子变化非常缓慢:
@echo off
setlocal
set "last=%time:~9,1%"
for /l %%N in (1 1 30) do (
call :wait
cmd /c echo %%time%% %%random%% %%random%% %%random%% %%random%% %%random%% %%random%%
)
exit /b
:wait
if %time:~9,1% equ %last% goto :wait
set "last=%time:~9,1%"
exit /b
- 输出1 -
22:13:26.31 30024 16831 1561 8633 8959 14378
22:13:26.41 30024 16831 1561 8633 8959 14378
22:13:26.51 30024 16831 1561 8633 8959 14378
22:13:26.61 30024 16831 1561 8633 8959 14378
22:13:26.71 30024 16831 1561 8633 8959 14378
22:13:26.81 30024 16831 1561 8633 8959 14378
22:13:26.91 30024 16831 1561 8633 8959 14378
22:13:27.01 30027 27580 19425 32697 19274 18304
22:13:27.11 30027 27580 19425 32697 19274 18304
22:13:27.21 30027 27580 19425 32697 19274 18304
22:13:27.31 30027 27580 19425 32697 19274 18304
22:13:27.41 30027 27580 19425 32697 19274 18304
22:13:27.51 30027 27580 19425 32697 19274 18304
22:13:27.61 30027 27580 19425 32697 19274 18304
22:13:27.71 30027 27580 19425 32697 19274 18304
22:13:27.81 30027 27580 19425 32697 19274 18304
22:13:27.91 30027 27580 19425 32697 19274 18304
22:13:28.01 30030 5560 4521 23992 29588 22231
22:13:28.11 30030 5560 4521 23992 29588 22231
22:13:28.21 30030 5560 4521 23992 29588 22231
22:13:28.31 30030 5560 4521 23992 29588 22231
22:13:28.41 30030 5560 4521 23992 29588 22231
22:13:28.51 30030 5560 4521 23992 29588 22231
22:13:28.61 30030 5560 4521 23992 29588 22231
22:13:28.71 30030 5560 4521 23992 29588 22231
22:13:28.81 30030 5560 4521 23992 29588 22231
22:13:28.91 30030 5560 4521 23992 29588 22231
22:13:29.01 30033 16308 22385 15287 7135 26158
22:13:29.11 30033 16308 22385 15287 7135 26158
22:13:29.21 30033 16308 22385 15287 7135 26158
此脚本演示了随机数生成器在单个CMD.EXE进程中“正常”工作。
@echo off
setlocal enableDelayedExpansion
set "last=%time:~9,1%"
for /l %%N in (1 1 30) do (
call :wait
echo !time! !random! !random! !random! !random! !random! !random!
)
exit /b
:wait
if %time:~9,1% equ %last% goto :wait
set "last=%time:~9,1%"
exit /b
- 输出2 -
22:16:10.30 24175 26795 4467 2450 12031 9676
22:16:10.40 6873 17221 14201 17898 32541 29918
22:16:10.50 700 21044 25922 8616 24057 7657
22:16:10.60 25370 6519 26054 28443 4865 1931
22:16:10.70 26989 9396 12747 26808 6282 32182
22:16:10.80 22778 11460 11989 26055 10548 1809
22:16:10.90 4668 27372 30965 12923 5941 16533
22:16:11.00 23426 11396 24402 29658 5150 11183
22:16:11.10 1557 13572 18815 21801 4103 23119
22:16:11.20 3459 30126 20484 32750 3360 16811
22:16:11.30 14041 26960 31897 24736 16657 1954
22:16:11.40 5112 18377 30475 18837 12216 10237
22:16:11.50 13136 6241 27074 29398 8996 9738
22:16:11.60 16027 15122 13659 28897 4827 29753
22:16:11.70 27502 8271 11489 21888 16590 7886
22:16:11.80 30405 25582 7288 5432 7310 26557
22:16:11.90 202 11076 23205 20739 28053 12621
22:16:12.00 4234 20370 10355 5974 27590 8732
22:16:12.10 24411 21836 16161 24731 22898 10378
22:16:12.20 23060 17903 10788 19107 29825 15561
22:16:12.30 6772 1371 674 13257 15504 18422
22:16:12.40 1344 31971 23977 8630 10789 15367
22:16:12.50 18945 17823 20691 10497 5958 31613
22:16:12.60 18294 10398 26910 8744 21528 272
22:16:12.70 25603 9991 24084 11667 16977 5843
22:16:12.80 19405 5457 16285 11165 26783 10627
22:16:12.90 20041 31763 26390 11994 19285 12287
22:16:13.00 21342 13853 9336 24080 2555 2067
22:16:13.10 9328 30429 1722 2211 22934 24871
22:16:13.20 8168 21818 19125 11102 449 8813
最后,这个脚本演示了给定行中的每个%random%
如何扩展到它自己的值,但是循环迭代之间的行值不会改变,因为循环行只被解析一次。
@echo off
setlocal
set "last=%time:~9,1%"
for /l %%N in (1 1 30) do (
call :wait
echo %time% %random% %random% %random% %random% %random% %random%
)
exit /b
:wait
if %time:~9,1% equ %last% goto :wait
set "last=%time:~9,1%"
exit /b
- 输出3 -
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
22:20:10.98 28188 30311 32299 7392 5874 32157
答案 1 :(得分:5)
cmd中的随机数生成器使用当前时间(第二个分辨率)来为prng播种。因此,从同一秒开始的两个进程将生成相同的“随机”数字。
对于不会发生冲突的选项,请使用vbscript的随机数生成器(先随机化),或使用guid(可以通过uuidgen或vbscript生成它),或者使用powershell,或者......
答案 2 :(得分:4)
@set @e=0 /*
@echo off
set @e=
cscript //nologo //e:jscript "%~f0"
exit /b
*/
function getRandomNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
WScript.echo(getRandomNumber(0, 10000));
答案 3 :(得分:3)
即使是完美的随机数发生器也能(最终)产生碰撞。一个强大的解决方案必须假设可能发生冲突,并相应地进行补偿。
以下是我过去成功使用的一种策略:
在脚本顶部分配唯一的临时文件名。将%TIME%
值用于伪“随机”数字。将:
替换为空,以使字符串对文件名有效。只有两个进程在彼此的1/100秒内启动时才会发生冲突(假设您的进程运行时间不超过一天)。
你可能会发生碰撞。可以通过临时锁定文件检测冲突。将脚本的主体放在子例程中,并使用非标准文件句柄调用主例程,该文件句柄重定向到具有“随机”编号的锁定文件 - 在任何给定时间,只有一个进程可以将输出重定向到锁定文件。如果检测到锁定,只需循环返回并重试。
@echo off
setlocal
:getUnique
:: Derive a pseudo "unique" name from script name and current time
set "tempBase=%temp%\%~nx0.%time::=%"
:: If you want to test the lock mechanism, uncomment the following
:: line which removes the time component from the "unique" name
::set "tempBase=%temp%\%~nx0.notUnique"
:: Save stderr, then redirect stderr to null
3>&2 2>nul (
%= Establish lock =%
9>"%tempBase%.lock" (
%= Restore stderr and call main routine =%
2>&3 (call :main %*)
%= Capture the returned errorlevel if necessary =%
call set "err=%%errorlevel%%
%= Force ERRORLEVEL to 0 so that any error detected outside =%
%= this block must be due to lock failure =%
(call )
%= Loop back and try again if lock failed due to collision =%
) || goto :getUnique
)
:: Delete the temp files and exit with the saved errorlevel
del "%tempBase%*"
exit /b %err%
:main
:: The rest of the script goes here.
:: Additional unique temp file names can be derived from %tempBase% as needed.
:: For this demo, I'll just list the temp file(s) and pause
dir /b "%tempBase%*"
pause
:: Exit with an error for testing purposes
exit /b 1
两个进程不太可能获得相同的唯一名称,但如果有,则第二个进程将检测到冲突,循环返回并再次尝试直到成功。
如果要测试锁定,请取消注释nonUnique tempBase行。打开两个控制台窗口,然后在两个窗口中启动脚本。第一个将成功进入主程序并暂停。第二个将循环,等待第一个完成。按下第一个键,第一个将立即结束,第二个将继续进入主程序。
如果您希望精度高于1/100秒,或者您的流程运行时间超过一天,那么您应该考虑使用WMIC OS GET LOCALDATETIME
来获取包含日期和时间为1/1000秒的字符串。
答案 4 :(得分:2)
你甚至可以在一秒内启动8个任务,每个任务都有自己的随机值。
随机数由main-task生成并作为参数发送。
setlocal EnableDelayedExpansion
for /L %%n in (1 1 8) DO start task.bat !random!
如果你的task.bat还需要一个独立的随机生成器,你可以使用参数作为种子前缀,如。
<强> task.bat 强>
setlocal EnableDelayedExpansion
set seed=%1
for /L %%n in ( 1 1 %seed%) do set dummy=!random!
答案 5 :(得分:0)
$RANDOM
没有这个缺陷。
@echo win=%RANDOM%
@for /f %%i in ('bash -c "echo $RANDOM"') do @set VAR=%%i
@echo cygwin=%VAR%
当我运行start randomcheck.bat & start randomcheck.bat
时,打印相同的窗口编号但不同的cygwin窗口编号。使用cygwin比为单个命令编写单独的VBScript要好。您可以教我如何用Windows脚本主机替代bash -c "echo $RANDOM"
替换,这将消除安装cygwin的需要。