1

I was conducting tests on Python (3.8.6) work speed. The test case was matrix per vector multiplication with sizes 10.000x10.000 and 10.000 correspondingly. The matrix and the vector were randomly filled with float numbers.

Firstly, I tried this code:

import time
import numpy as np

def str_per_vec(a, b, n):
    res = 0
    for i in range(n):
        res += a[i] * b[i]
        
    return res

N = 10000

A = np.random.randn(N, N)
b = np.random.randn(N)
correct_answer = A @ b

A = A.tolist()
b = b.tolist()
c = [None] * N

start = time.perf_counter()

for i in range(N):
    c[i] = str_per_vec(A[i], b, N)

end = time.perf_counter()    
    
assert np.allclose(c, correct_answer)
print("Time:", end - start)

And the output was "Time: 6.585052800000001"

Then I tried another code. In fact, I just removed the function and wrote it in the loop itself:

import time
import numpy as np

N = 10000

A = np.random.randn(N, N)
b = np.random.randn(N)
correct_answer = A @ b

A = A.tolist()
b = b.tolist()
c = [None] * N

start = time.perf_counter()

for i in range(N):
    buf = 0
    a = A[i]
    for j in range(N):
        buf += a[j] * b[j]
    c[i] = buf

end = time.perf_counter()    
    
assert np.allclose(c, correct_answer)
print("Time:", end - start)

And this time the output was "Time: 12.4580008".

So, I just moved code from the function to the loop, but it took twice more time to execute! I'm really confused with it, because I have no idea why this happened. If someone proficient in Python could help me, I would be very grateful!

P.S. I conducted tests several times and the results were stable.

kaif2100
  • 11
  • 2
  • 2
    probably this: https://stackoverflow.com/q/12590058/812183 – anthony sottile May 05 '22 at 12:49
  • @AnthonySottile I don't think this is the case. In both instances all variables used in the second loop are local (I treat global variables as locals for the "global code" (outside a function)). – kaif2100 May 05 '22 at 12:55
  • Globals are globals, what do you mean with "treating" them as locals? – Kelly Bundy May 05 '22 at 13:05
  • What time do you get when you indent the entire second code as-is into a function (e.g., call it `main`) and call that? – Kelly Bundy May 05 '22 at 13:07
  • @KellyBundy If I write "start = time.perf_counter()" straight after the imports and "end = time.perf_counter()" straight after the np.allclose, then the first code output is between 10.5 and 10.7 seconds, the second code output is between15.5 and 17.5 seconds. – kaif2100 May 05 '22 at 13:57
  • @KellyBundy Of course globals are globals. I meant that there is no difference (as I see it) whether we operate with locals or globals when we work outside any function (in "global" code). Maybe I'm wrong – kaif2100 May 05 '22 at 13:59
  • And what time do you get when you do what I asked about? – Kelly Bundy May 05 '22 at 14:07
  • @KellyBundy I put the second code without imports, assert construction and perf_counters into a function and called it, measuring the time. The result is ~11.3 seconds. For the first code put into the function (without str_per_vec declaration) the result is the same ~11.3 seconds. So far, we have made the first variant as slow as the second one :) – kaif2100 May 05 '22 at 14:17
  • Oh, yeah, I got it. I have misinterpreted results at first. The 11.3 seconds include initializing arrays, but substracting tis time we obtain desired ~6.6 seconds! – kaif2100 May 05 '22 at 14:25
  • So, finally, is it all because of locals and globals? But why does it take time to run through locals outside a function (in global code)? What are the locals in this case? – kaif2100 May 05 '22 at 14:27
  • Is *"**entire** second code **as-is**"* somehow unclear? – Kelly Bundy May 05 '22 at 14:38
  • Outside a function, there are no locals. Not sure what you mean. – Kelly Bundy May 05 '22 at 14:40
  • I'm not a native English speaker, so yeah, I messed up with "as-is". – kaif2100 May 05 '22 at 14:54
  • Thank you for the respond! I think, the question is closed :) – kaif2100 May 05 '22 at 14:54

1 Answers1

0

Thanks to Anthony Sottile and Kelly Bundy for their responses in the comments, they have clarified everything. The thing was in local variables and global variables (see Performance with global variables vs local). The first code use local variables inside a function, whereas the second one uses global variables. And since access to local variables is in principle faster, than to global variables, the first code worked faster. If the second code is wrapped into a function, it works the same time the first does.

kaif2100
  • 11
  • 2