How to run multiple functions simultaneously by multi-core CPU in Windows?

There exist multiple functions, take them for instance, 3 functions as follows:

f1=3*D[h1[x],x]*Exp[1*x];
f2=3*D[h2[x],x]*Exp[2*x];
f3=3*D[h3[x],x]*Exp[3*x];
(*h1,h2,h3 are large symbolic matrices with respect to x*)
Do[fPlot=Plot[{f1[[i]],f2[[i]],f3[[i]]},{x, 0, 5}]; Print[fPlot],{i, Length[f1]}]


f1,f2 and f3 are independent, every function fx is time-consuming needless to say run their three one by one, so how to run the 3 functions at the same time by taking advantage of my multi-core CPU windows. I know the build-in function Parallelize and its family function ParallelTable, ParallelDo and so on, but I don't know how to solve the the problem mentioned above.

Parallel calculation has been achieved, but the result surprised me:

In[1]:= Plus@Table[3^x, {x, 10^5}]; // AbsoluteTiming
Plus@Table[5^x, {x, 10^5}]; // AbsoluteTiming
{k1, k2} =
Parallelize[{Plus@Table[3^x, {x, 10^5}],
Plus@Table[5^x, {x, 10^5}]}]; // AbsoluteTiming
{f1, f2} =
ParallelTable[
ReleaseHold[expr], {expr,
Plus@Table[5^x, {x, 10^5}]}]]}]; // AbsoluteTiming

Out[1]= {7.8803, Null}

Out[2]= {13.0114, Null}

Out[3]= {278.987, Null}

Out[4]= {278.304, Null}


7.8803 + 13.0114 << 278 (time parallel calculation consumed)

how does the result generate?

Assignment is typically much faster than computations involving large symbolic matrices, so let's construct the list of expressions so that we can offload them to ParallelTable:

{f1, f2, f3} = ParallelTable[ReleaseHold[expr],
{3*D[h1[x],x]*Exp[1*x], 3*D[h2[x],x]*Exp[2*x], 3*D[h3[x],x]*Exp[3*x]}
]]}
];


Thread[Hold[...]] is used to prevent the expressions from being evaluated as part of the expr iterator. If we don't do that the values will be expanded before ever being dispatched to the parallel kernels, which means that there won't be any speedup.

Note that if your expressions have side-effects (e.g. assignment within the expression), trying this may result in some very unusual bugs as the parallel kernels will typically not share their side-effects with each other.

Regarding the second part of the edited question, it appears that passing back large arrays from parallel kernels may be comparatively slow. I assume that the intent of Plus@Table is to replicate the effects of Sum (which would be Plus@@Table, in most cases). In that case, the fastest code I could find for this particular case is:

({f1, f2} = {ParallelSum[3^x, {x, 10^5}], ParallelSum[5^x, {x, 10^5}]}); // AbsoluteTiming


{4.61335, Null}

Note that ParallelSum is used directly instead of using Sum in a ParallelTable. This is because more localized parallel operations tend to be faster, as memory access can be made more consistent. The above ParallelTable trick assumes that there's no particular correlation to be had between the individual expressions to begin with, and that random memory access is not going to be the primary contributing factor the slowness of the evaluation. Notably, this is rather faster than Parallelize's result using Sum:

{k1, k2} =
Parallelize[{Sum[3^x, {x, 10^5}], Sum[5^x, {x, 10^5}]}]; // AbsoluteTiming


{10.9441, Null}

• Thank you, eyorble. Your novel method solved my problem. I didn't even think that you could provide such a detailed explanation, this is really a pleasant surprise. – likehust Apr 12 at 1:16
• Can you provide me with a new method again, thanks. – likehust Apr 12 at 7:12
• @likehust Plus@Table is equivalent to Table in this use. Did you mean Total@Table or Plus@@Table or Sum, perhaps? It seems that passing the very large arrays of arbitrary precision numbers back from the parallel kernels is actually somewhat slow. – eyorble Apr 12 at 7:29
• (Note: A question at the end) Sorry for the typed wrong letter, the wanted code is Plus@@Table. I wanted to test the efficiency of the solution you provided for the first time, didn't expect to disturb you because of the input errors. In addition, I have to bother you another question - Why does ParallelTable be slower than Table in the flowing example: Table[3^x,{x,10^5}];//AbsoluteTiming ParallelTable[3^x,{x,10^5}];//AbsoluteTiming the consumed time are respectively: 7.62728, 95.4714 – likehust Apr 12 at 9:18
• Likely because the numbers involved get rather large, so they end up needing arbitrary memory allocations. These allocations presumably clobber the cache however when working in parallel, since they're of relatively unpredictable size in a relatively unpredictable order, and the large amounts of memory are not available in parallel or pre-allocatable. I'm not clear on the internals however, so that's just my guess. – eyorble Apr 12 at 9:49