Skip to main content

This script is particularly useful for taking advantage of processor and spindle performance when synchronizing directories that contain hundreds or thousands of subdirectories.

@echo off
cls
color 2a
title Multi-Threaded Robocopy
SETLOCAL ENABLEDELAYEDEXPANSION

:: Ben Kendall's Multi-Threaded Robocopy :: Copyright April 2011
::
:: Kicks off a robocopy instance for every processor on your machine
:: Monitors for termination of robocopy instances and spawns new ones to take their place
::
:: Robocopy.exe must be somewhere in PATH - Already the case in newer versions of Windows
::
:: Change variables below to suit your needs
::
:: http://www.tech-recipes.com/rx/13768/multi-threaded-robocopy-by-first-level-subfolder/


set SOURCE=%systemdrive%\temp
set DEST=%systemdrive%\testdir
set OPTS=/mir /np /w:3 /r:3
set /a THREADS=%NUMBER_OF_PROCESSORS%


echo.
echo Copying %THREADS% folders at a time from "%SOURCE%" to "%DEST%"
echo.
echo With options "%OPTS%"
echo.
pause


set FOLDER=0
set FOLDERNUM=0
set RUNCOUNT=0


:: Kick off primary loop that iterates through directories under %SOURCE%:

for /f "tokens=* delims=" %%a in ('dir /a:d /b "%SOURCE%"') do (
                            set FOLDER=%%a
                            :STARTLOOP
                            if !RUNCOUNT! LSS %THREADS% (
                                        call :WORK
                                        ) else (
                                        call :KILLTIME
                                        )
                            )


:: Finished primary loop so folder copies are done:
goto :DONE


:: Spawn a robocopy thread and increment our count:
:WORK
set /a RUNCOUNT=!RUNCOUNT!+1
set /a FOLDERNUM=!FOLDERNUM!+1
echo.
echo Folder number !FOLDERNUM! is: "%SOURCE%\%FOLDER%"
start "Robocopy Folder Number:!FOLDERNUM!" robocopy.exe "%SOURCE%\%FOLDER%" "%DEST%\%FOLDER%" %OPTS%
goto :EOF


:: Robocopy threads are currently running so we wait and check again before spawning new:
:KILLTIME
call :GETRUNNING
if %RUNCOUNT% LSS %THREADS% (
            goto :WORK
            ) else (
            goto KILLTIME
            )



:::::::::::::
:: Subroutine to get count of running instances of robocopy.exe:
:GETRUNNING
ping -n 6 localhost >nul
set RUNCOUNT=0
for /f "tokens=1 delims=," %%b in ('tasklist /fo csv /nh /fi "imagename eq robocopy.exe"^| findstr /v "INFO:"') do (
                                            set /a RUNCOUNT=!RUNCOUNT!+1
                                            )
goto :EOF
::End of GETRUNNING subroutine
:::::::::::::


:DONE

:: Robocopy remaining files that live in root of source directory:
:COPYFILES
echo.
echo Copying remaining files from "%SOURCE%" to "%DEST%"...
start "Robocopy Files in %SOURCE%" /wait robocopy.exe "%SOURCE%" "%DEST%" /purge /np /w:3 /r:3

:ALLDONE

:: Check for remaining instances of robocopy.exe and wait for completion before continuing:
call :GETRUNNING
if .%RUNCOUNT%. NEQ .0. (goto :ALLDONE)

echo.
echo Done
echo.
echo We stopped Copying at folder "%SOURCE%\%FOLDER%"
echo.
pause

set SOURCE=
set DEST=
set OPTS=
set THREADS=
set RUNCOUNT=
set FOLDER=
set FOLDERNUM=


ENDLOCAL

goto :END


:END