views:

993

answers:

3

Hi all -

I would like to make a section of my code more efficient. I'm thinking of making it fork off into multiple processes and have them execute 50/100 times at once, instead of just once.

For example (pseudo):

for line in file; do foo; foo2; foo3; done

I would like this for loop to run multiple times. I know this can be done with forking. Would it look something like this?

while(x <= 50) parent(child pid) { fork child() } child { do foo; foo2; foo3; done return child_pid() }

Or am I thinking about this the wrong way?

Thanks!

A: 

Let me try example

for x in 1 2 3 ; do { echo a $x ; sleep 1 ; echo b $x ; } &  done ; sleep 10

And use jobs to see what's running.

Michael Krelin - hacker
+1  A: 

I don't know of any explicit fork call in bash. What you probably want to do is append & to a command that you want to run in the background. You can also use & on functions that you define within a bash script:

do_something_with_line()
{
  line=$1
  foo
  foo2
  foo3
}

for line in file
do
  do_something_with_line $line &
done

EDIT: to put a limit on the number of simultaneous background processes, you could try something like this:

for line in file
do
  while [`jobs | wc -l` -ge 50 ]
  do
    sleep 5
  done
  do_something_with_line $line &
done
mobrule
You've miscapitalized the do_something… name ;-)
Michael Krelin - hacker
Got it -What about when I want to make sure I am only running 50 instances at a time? And - when one of those processes are done, make sure 1 more is spawned.
Greg
Use the `jobs` bash builtin.
Michael Krelin - hacker
Ah yes - I didn't see the last line of your answer. Thank you very much. I'll get to work.
Greg
I've added the line after you asked, so it's alright that you failed to read my mind ;-) (just as I failed to read yours before you asked:)). BTW, `man bash` is one great source for the information on job control. Once you're gone this path you may have many questions ;-)
Michael Krelin - hacker
For the value of a variable, you must use **$varname** -- otherwise you'll just pass the literal (string) **"varname"**
NVRAM
@NVRAM - thanks - didn't catch that
mobrule
You probably also want **$file** (or use **while read line**).
NVRAM
A: 

In bash scripts (non-interactive) by default JOB CONTROL is disabled so you can't do the the commands: job, fg, and bg.

Here is what works well for me:

#!/bin/sh

set -m # Enable Job Control

for i in `seq 30`; do # start 30 jobs in parallel
  sleep 3 &
done

# Wait for all parallel jobs to finish
while [ 1 ]; do fg 2> /dev/null; [ $? == 1 ] && break; done
Aleksandr Levchuk