title: Simple parallel evaluation of two functions in Python
body: <p>Code where most of the execution time is spent performing two independent function evaluations is an obvious candidate to use two CPUs. I know how to do it in Python with <a href="https://docs.python.org/3/library/multiprocessing.html" rel="nofollow noreferrer"><code>multiprocessing</code></a>, but only with the idiom <code>if __name__ == '__main__':</code> added to the entry point of the program. Is there a simpler way in modern Python (3.8.3 at time of writing)? Nothing <a href="https://stackoverflow.com/q/7207309/903600">there</a> seems suitably simple.</p>
  
  <p>Requirements: no change to the calling code, and no separate file. It's fine to <code>import</code> some helper, but I would prefer not to <code>pip</code>.</p>
  
  <p>Example application and benchmark, in the field of cryptography:</p>
  
  <pre class="lang-py prettyprint-override"><code>def rsacrt(p,q,dp,dq,qi,x):
      # most of the time is spent in the following two lines
      u = pow(x,dp,p)
      v = pow(x,dq,q)
      return (u-v)*qi%p*q+v
  
  # test and benchmark the above
  import time
  e,p,q = 3, 5**3528+12436, 7**2918+27562
  n,dp,dq,qi = p*q, pow(e,-1,p-1), pow(e,-1,q-1), pow(q,-1,p)
  x = 42
  t = time.time()
  y = rsacrt(p,q,dp,dq,qi,x)
  t = time.time()-t
  if pow(y,e,n)!=x: print("# wrongo, spasmoid!")
  print("duration of rsacrt:",(int)(t*1000.),"ms")
  </code></pre>
  
  <p>The operation shown is the one bottleneck in RSA signature generation, and RSA decryption. Parameters are deliberately high (16384-bit RSA, rather than the usual 2048-bit), so the execution time is in the order of seconds, with >98% in the two first <code>pow</code>. This is meant to illustrate a real-life case where parallel execution matters, not as an example on how to do RSA: there are fast alternatives to <code>pow</code>, and this code lacks side-channel protection.</p>
  
  <p>Note: This code requires a version of Python where <a href="https://docs.python.org/3/library/functions.html#pow" rel="nofollow noreferrer"><code>pow</code></a> can compute the modular inverse. That includes Python 3.8.x. <a href="https://tio.run/##bVHZbsIwEHz3V2yDKsVmg0jCVSQ@JhAHrBLfOfj61DEVrar6wdbMemfGa/3wNyXLg7bTVPMGrKsu1qcaDdYaa4NG4EiPBMJaQKucB9WAv3HwouUgHDjNpQchI9mo@10NQl7BDwruQnIXWzs4gVZDOs6qmkau/@GCzZOz3HdWQtplPWVGvGtmlj0hC/A8OFeyhjOXl1tb2c/oV51Vz4lotbI@JiIcQ/agXCJsGSu3xWGZF5tyh7BnrPjID8tiv90VRL7eN8dgBmMWjlmOOsvpL2he0MQqJWNo2RTEh2P2XM1bSskj4P/n9/dq5oloouQDOUr6dhqPoK2QPk0WMFglrwrDZCvXKlG/JZR8F@vOVl4oOX/C0@qYYBpKNPUsX6/XK4pJ6xI6TV8" rel="nofollow noreferrer">Try it online!</a>.</p>
  
  <p>Addition: The code that works under Python 3 is sizably larger, see this other <a href="https://tio.run/##dVLtkpswDPzvp1DIdIqJSfi43KXp8A59BRPMxS22wZgAT5/KXJLL3LT@AeOVtVpJ287ubHR@vVaiBtvzk3VhyzpWtazqWCfZRI8E8KxBmd6BqcGdBTipBMge@lZoB1IvYG2axoxSv4MbDTRSi35JHaCA1ozh5FlbumCXTwzLfGBWuMFqCIf4QqNOfmujbnMhZA2lqI0V8GvRCvn2wHwunLj@7uBkVDs4gfKqoeEWxVyE7cVP@D2g3sqAdMQ3h3EMhZypW0clm9iMMhRLWLog41k2AviqSD9e@CNr4EWRHO/qkkekw9xyt@MPAAk9FPOoYzBtumh@ZikLpL2zqHj6EvtfBb7blQ@AL4J5XPoKM1aYngc3@1k5gV1zXeHQ9OmsuP1zWyuRqjXWLasjguGSkSpnsI@ifJ8dNmn2kr8yeIui7Ed62GRv@9eM6IcR/L581dsYkSBO6dO1e752fs1@GC8ZcfjzNbf@E1LiO/i30b4@jVFzvbhkZoJpuiqmI7RWahcGaxit0e@GoQV5r4ysVgElt2A1WO4kWsXcPX0MWIghGrooTZJkS1mg@oBer38B" rel="nofollow noreferrer">Try it online!</a>.</p>