草庐IT

windows - 批处理文件多任务问题与父共享变量

coder 2024-06-21 原文

我正在尝试在 x265 中对视频文件进行批量编码,并想提出一个可以自动执行该过程的批处理文件。为了加快速度,我发现用 2 个线程调用 3 个 ffmpeg 实例会产生理想的编码时间,但是我昨天一整天都在尝试想出一种方法来获取一个批处理文件,该文件将调用 3 个实例,然后完成后调用新的。到目前为止,这就是我所在的位置:

父级

@echo off
Setlocal EnableDelayedExpansion
SET /A COUNT=0
for %%a in (*.mkv) do (
    CALL :CHECK
    SET /A COUNT+=1
    START CALL "child.bat" "%%a"
    )
EXIT /B 0

:CHECK
IF !COUNT! EQU 3 (
    TIMEOUT /T 5
    GOTO :CHECK
)
EXIT /B 0

子批处理

ffmpeg <COMMAND LINE ARGS>
SET /A COUNT-=1
EXIT /B 0

我有两个问题。 1) COUNT 变量没有在父进程中更新,并且当子进程完成时它永远不会产生新实例。 2) 子进程没有干净地退出。它会打开一个单独的 cmd.exe 窗口,并显示 DOS 提示符。

有什么想法吗?

编辑:替换了嵌套的 GOTO 以防止 FOR 循环中断

下面的解决方法

Setlocal EnableDelayedExpansion
SET /A COUNT=0
for %%a in (*.mkv) do (
    IF !COUNT! EQU 3 CALL :CHECK
    SET /A COUNT+=1
    START CALL "child.bat" "%%a"
    )
EXIT /B 0

:CHECK
IF EXIST DONE.TXT (
    SET /A COUNT-=1
    DEL DONE.TXT
    EXIT /B 0
    ) ELSE (
    TIMEOUT /T 5
    GOTO :CHECK
    )
EXIT /B 0

子批处理

ffmpeg <COMMAND LINE ARGS>

:DONE
IF EXIST DONE.TXT (
    TIMEOUT /T 1
    GOTO :DONE
)
echo 1 >> DONE.TXT
EXIT 0

最佳答案

关于您陈述的问题:

1) 子进程不能修改父进程中的环境变量。您将需要一种不同的机制来检测 child 何时终止。此外,正如 Squashman 在他的评论中所述,循环中的 GOTO 将中断(终止)循环,这就是为什么在前 3 个之后没有启动新的子进程的原因。

2) 您的子窗口没有终止,因为您使用了 EXIT/B。请改用 EXIT,窗口将关闭。

在找到可行的解决方案之前还有很长的路要走 ;-)

也许最大的障碍是检测子进程何时终止。

我知道 3 种策略:

1) 使用 TASKLIST 结合 FIND/C 来统计当前正在运行的 ffmpeg 进程数。这可能是最简单的解决方案,但它无法区分您的脚本启动的进程与可能由其他机制启动的进程。

2) 使用文件作为信号。为每个进程创建一个空文件,然后当进程完成时,让它删除该文件。您的主脚本可以通过查找文件来监视哪些进程处于事件状态。这也很简单,但如果您的某个进程在删除文件之前崩溃,它就不会正常运行。这会使您的系统处于不健康状态。

3) 我最喜欢使用锁定文件。每个子进程通过重定向锁定一个文件,当进程终止时(崩溃,正常退出,不管怎样),然后释放锁。主进程可以尝试锁定相同的文件。如果锁定成功,它知道 child 已经终止,否则 child 仍在运行。这种策略是最复杂的,它使用神秘的语法,但我发现它非常有效。

我已经在 Parallel execution of shell processes 实现了一个解决方案使用选项 3)。以下是针对您的情况对该代码进行的改编/简化。

我使用 START/B 在父窗口中启动每个子进程,并将所有输出重定向到锁定文件。完成后,我键入输出文件,以便您查看发生了什么。我还列出了每个子进程的开始和停止时间。

您只需调整 3 个顶级环境变量以满足您的需要。剩下的应该很好去。但是,如果任何文件名包含 ! 字符,则编写的代码将失败。可以通过更多工作来消除此限制。

脚本中有大量文档。 %= COMMENT =%语法是一种在不使用 REM 的情况下安全地将注释嵌入循环的方法。

@echo off
setlocal enableDelayedExpansion

:: Define the command that will be run to obtain the list of files to process
set listCmd=dir /b /a-d *.mkv

:: Define the command to run for each file, where "%%F" is an iterated file name from the list
::   something like YOUR_COMMAND -i "%%F"
set runCmd=ffmpeg  [** command arguments go here **]

:: Define the maximum number of parallel processes to run.
set "maxProc=3"

::---------------------------------------------------------------------------------
:: The remainder of the code should remain constant
::

:: Get a unique base lock name for this particular instantiation.
:: Incorporate a timestamp from WMIC if possible, but don't fail if
:: WMIC not available. Also incorporate a random number.
  set "lock="
  for /f "skip=1 delims=-+ " %%T in ('2^>nul wmic os get localdatetime') do (
    set "lock=%%T"
    goto :break
  )
  :break
  set "lock=%temp%\lock%lock%_%random%_"

:: Initialize the counters
  set /a "startCount=0, endCount=0"

:: Clear any existing end flags
  for /l %%N in (1 1 %maxProc%) do set "endProc%%N="

:: Launch the commands in a loop
  set launch=1
  for /f "tokens=* delims=:" %%F in ('%listCmd%') do (
    if !startCount! lss %maxProc% (
      set /a "startCount+=1, nextProc=startCount"
    ) else (
      call :wait
    )
    set cmd!nextProc!=%runCmd%
    echo -------------------------------------------------------------------------------
    echo !time! - proc!nextProc!: starting %runCmd%
    2>nul del %lock%!nextProc!
    %= Redirect the lock handle to the lock file. The CMD process will     =%
    %= maintain an exclusive lock on the lock file until the process ends. =%
    start /b "" cmd /c >"%lock%!nextProc!" 2^>^&1 %runCmd%
  )
  set "launch="

:wait
:: Wait for procs to finish in a loop
:: If still launching then return as soon as a proc ends
:: else wait for all procs to finish
  :: redirect stderr to null to suppress any error message if redirection
  :: within the loop fails.
  for /l %%N in (1 1 %startCount%) do 2>nul (
    %= Redirect an unused file handle to the lock file. If the process is    =%
    %= still running then redirection will fail and the IF body will not run =%
    if not defined endProc%%N if exist "%lock%%%N" 9>>"%lock%%%N" (
      %= Made it inside the IF body so the process must have finished =%
      echo ===============================================================================
      echo !time! - proc%%N: finished !cmd%%N!
      type "%lock%%%N"
      if defined launch (
        set nextProc=%%N
        exit /b
      )
      set /a "endCount+=1, endProc%%N=1"
    )
  )
  if %endCount% lss %startCount% (
    timeout /t 1 /nobreak >nul
    goto :wait
  )

2>nul del %lock%*
echo ===============================================================================
echo Thats all folks

关于windows - 批处理文件多任务问题与父共享变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33452986/

有关windows - 批处理文件多任务问题与父共享变量的更多相关文章

  1. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  2. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  3. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  4. ruby - 如何使用 RSpec::Core::RakeTask 创建 RSpec Rake 任务? - 2

    如何使用RSpec::Core::RakeTask初始化RSpecRake任务?require'rspec/core/rake_task'RSpec::Core::RakeTask.newdo|t|#whatdoIputinhere?endInitialize函数记录在http://rubydoc.info/github/rspec/rspec-core/RSpec/Core/RakeTask#initialize-instance_method没有很好的记录;它只是说:-(RakeTask)initialize(*args,&task_block)AnewinstanceofRake

  5. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  6. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  7. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

    这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

  8. ruby-on-rails - 使用 ruby​​ 将多个实例变量转换为散列的更好方法? - 2

    我收到格式为的回复#我需要将其转换为哈希值(针对活跃商家)。目前我正在遍历变量并执行此操作:response.instance_variables.eachdo|r|my_hash.merge!(r.to_s.delete("@").intern=>response.instance_eval(r.to_s.delete("@")))end这有效,它将生成{:first="charlie",:last=>"kelly"},但它似乎有点hacky和不稳定。有更好的方法吗?编辑:我刚刚意识到我可以使用instance_variable_get作为该等式的第二部分,但这仍然是主要问题。

  9. ruby - Rack:如何将 URL 存储为变量? - 2

    我正在编写一个简单的静态Rack应用程序。查看下面的config.ru代码:useRack::Static,:urls=>["/elements","/img","/pages","/users","/css","/js"],:root=>"archive"map'/'dorunProc.new{|env|[200,{'Content-Type'=>'text/html','Cache-Control'=>'public,max-age=6400'},File.open('archive/splash.html',File::RDONLY)]}endmap'/pages/search.

  10. Vscode+Cmake配置并运行opencv环境(Windows和Ubuntu大同小异) - 2

    之前在培训新生的时候,windows环境下配置opencv环境一直教的都是网上主流的vsstudio配置属性表,但是这个似乎对新生来说难度略高(虽然个人觉得完全是他们自己的问题),加之暑假之后对cmake实在是爱不释手,且这样配置确实十分简单(其实都不需要配置),故斗胆妄言vscode下配置CV之法。其实极为简单,图比较多所以很长。如果你看此文还配不好,你应该思考一下是不是自己的问题。闲话少说,直接开始。0.CMkae简介有的人到大二了都不知道cmake是什么,我不说是谁。CMake是一个开源免费并且跨平台的构建工具,可以用简单的语句来描述所有平台的编译过程。它能够根据当前所在平台输出对应的m

随机推荐