This is process substitution.
The end result of both forms you give should be mostly the same; the differences are that
- as you point out, process substitution runs both processes simultaneously;
- your second form uses a file on a file system, so you need space to store that (and ideally, remove it afterwards).
Technically, the I/O between processes involving process substitution behaves like pipes, not like files. (This might well be an implementation detail though.)
Correctly-written programs shouldn’t exhibit differences in their results because they run simultaneously; for example,
tail -n 1 <(seq 1 10000000)
correctly shows the last number in the sequence, whereas attempting to do this manually with
seq 1 10000000 > blah &
tail -n 1 blah
will fail because tail shows whatever is the last line stored at the time it runs, it doesn’t wait for seq to finish. Your second form correctly waits in this instance.
You can however see differences in external behaviour. For example,
head -n 1 <(seq 1 1000000000)
finishes immediately (even seq, thanks to the pipe behaviour), whereas
seq 1 1000000000 > blah
head -n 1 blah
takes quite a long time to run. This type of difference can mean that replacing one form with the other isn’t appropriate.