1

I am connecting to a (osX) server with many CPU's. I want to run my program for many different input files. Right now, i run one by one:

for input in "${inputs[@]}"
do
    .<my-program.sh> --input $input
done

This is very slow and not using the full CPU power, so i would like to run in parallel instead.

I would like to open a new detached screen and to run my program inside, something like:

for input in "${inputs[@]}"
do
    screen -S test -X screen .<my-program.sh> --input $input
done

Would each screen then work on a different CPU (I would like to use the available CPU power) and is the command correct? Or should I open a new shell for each input (I think then it definately runs on different CPU's)?

  • Is there a reason you want to run the processes via screen rather than just running them in parallel? – symcbean Aug 26 '17 at 22:39
2

To directly answer your question, unless you use CPU pinning to manually assign a specific process to a specific CPU, your operating system will normally schedule tasks to run on whatever it thinks is the "best" CPU to handle it at that moment, and it's possible that the task may even be moved back and forth between multiple CPU cores, depending on what else the machine is doing at the same time.

The practical result of this is that, if you run five instances of your program, they may run on five separate CPUs, but there's no guarantee that they will run on separate CPUs. If each individual process uses under 20% CPU capacity it's even possible (though unlikely) that all five might run on the same processor.

To address your broader situation, if you have a program which processes several files and uses only a small amount of CPU power, there's a good chance that your bottleneck is disk I/O capacity. If this is the case, speeding it up will require a faster disk (or larger disk cache, if you're repeatedly reading the same data) and parallelizing it across multiple processes and CPUs may actually reduce performance by forcing the disk to spend time switching off between reading the first instance's input file(s) and reading other files for each of the other processes.

A quick and easy way to test whether you're being bottlenecked by disk I/O is to cat file_1 file_2 file_3... >/dev/null (where file_1, etc. is a list of all the files your program processes) and compare how long it takes to just read the files (without doing any processing) to the time it takes to process them.

| improve this answer | |
2

Whenever you run multiple processes, they will potentially run on different cores. Even a single process is can migrate from core to core many times per second. This also applies to individual threads inside a process. The kernel will always try to run as many threads in possible in parallel. For example, if you have 4 cores and 3 threads currently require CPU time then 3 cores will be busy. If 6 threads require CPU time then all 4 cores will be busy and 2 threads will wait for their turn.

Starting the programs from different shells or from different screen windows has no impact on how the programs are scheduled. What causes the programs to run in parallel in your second snippet is the fact that each call to screen starts an instance of myprogram.sh and does not wait for it to terminate. You could do the same thing without involving screen, just by using the & operator in the shell to run the program in the background, i.e. to start the program and move immediately to the next instruction in the script without waiting for the program to end.

for input in "${inputs[@]}"
do
  .<my-program.sh> --input "$input" &
done

Starting all the runs at the same time is not necessarily the fastest way. It depends what resources your program uses. If the program uses CPU time and doesn't do much input/output then you'll get best results by running as many instances as the number of cores. If the program uses a lot of memory, run only as many instances as fit in memory; if the machine has to swap or doesn't have enough room for the disk cache then it will run a lot slower. If the program is I/O-intensive then make sure that you don't saturate whichever I/O bandwidth is the bottleneck (network, disk, …).

There are tools that facilitate running a set number of instances of a program in parallel. You can use xargs:

printf '%s\000' "${inputs[@]}" | xargs -0 -L 1 -P 4 myprogram.sh 

make can also run programs in parallel. With the following file called Makefile (replace 8 spaces at the beginning of a line by a tab character):

all = $(patsubst %.in,%.out,$(wildcard *.in))
%.out: %.in
        myprogram.sh --input $< --output $@

Run make -j4 all to run myprogram.sh on all the .in files and produce corresponding .out files, running up to 4 instances in parallel.

For more complex scenarios you may want to install GNU parallel.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.