12

I tried solving Maximum Subarray using both Javascript(Node.js) and Python, with brute force algorithm. Here's my code:

Using python:

from datetime import datetime
from random import randint

arr = [randint(-1000,1000) for i in range(1000)]

def bruteForce(a):
  l = len(a)
  max = 0
  for i in range(l):
    sum = 0
    for j in range(i, l):
      sum += a[j]
      if(sum > max):
        max = sum
  return max

start = datetime.now()
bruteForce(arr)
end = datetime.now()

print(format(end-start))

And Javascript:

function randInt(start, end) {
    return Math.floor(Math.random() * (end - start + 1))
}

var arr = Array(1000).fill(randInt(-1000, 1000))

function bruteForce(arr) {
    var max = 0
    for (let i = 0; i < arr.length; i++) {
        var sum = 0
        for (let j = i; j < arr.length; j++) {
            sum += arr[j]
            max = Math.max(max, sum)
        }
    }
    return max
}

var start = performance.now()
bruteForce(arr)
var end = performance.now()
console.log(end - start)

Javascript got a result of about 0.187 seconds, while python got 4.75s - about 25 times slower. Does my code not optimized or python is really that slower than javascript?

6
  • 3
    properly structured JS is blisteringly fast when run in modern browsers. Perhaps one day just-in-time bytecode compilation by browsers will be efficiently applied to Python but it will have a lot of catching up to do. I once re-worked million-loop JS functions in C and the run times were very close - browsers are particularly efficient for processing repetitions such as loops where only one or two variable change. There's interesting background material here: hacks.mozilla.org/2017/02/… Commented Mar 30, 2022 at 14:33
  • 1
    @general-grievance, what was the time for the JS? of course different user systems will vary, it's the comparison that matters. Would be interesting to see how different set ups compare. Commented Mar 30, 2022 at 14:35
  • 1
    On my computer they both take approximately 0.3s Commented Mar 30, 2022 at 14:41
  • 2
    @DavePritlove True. Testing on TIO: Python: ~0.1s, and JS 0.07-0.08 s after removing all the output code. So, slower, just not by a factor of 25. Commented Mar 30, 2022 at 14:42
  • @general-grievance, yes, that's pretty close. Thanks. Commented Mar 30, 2022 at 14:55

2 Answers 2

20

Python is not per se slower than Javascript, it depends on the implementation. Here the results comparing node and PyPy which also uses JIT:

> /pypy39/python brute.py
109.8594 ms N= 10000 result= 73682
> node brute.js
167.4442000091076 ms N= 10000 result= 67495

So we could even say "python is somewhat faster" ... And if we use Cython, with a few type-hints, it will be again a lot faster - actual full C speed:

> cythonize -a -i brutec.pyx
> python -c "import brutec"
69.28919999999998 ms N= 10000 result= 52040

To make the comparison reasonable, I fixed a few issues in your scripts:

  • Fix: the js script filled an array with all the same values from a single random
  • Does the same basic kind of looping in Python - instead of using the range iterator (otherwise its a little slower)
  • Use the same time format and increase the array length to 10000 - otherwise the times are too small regarding resolution and thread switching jitter

Python code:

from time import perf_counter as clock
from random import randint

N = 10000
arr = [randint(-1000,1000) for i in range(N)]

def bruteForce(a):
  l = len(a)
  max = 0
  i = 0
  while i < l:
    sum = 0
    j = i
    while j < l:
      sum += a[j]
      if sum > max:
        max = sum
      j += 1
    i += 1
  return max

start = clock()
r = bruteForce(arr)
end = clock()
print((end - start) * 1000, 'ms', 'N=', N, 'result=', r)
##print(arr[:10])

JS code:

var start = -1000, end = 1000, N=10000
var arr = Array.from({length: N}, 
    () => Math.floor(Math.random() * (end - start + 1) + start))

function bruteForce(arr) {
    var max = 0
    for (let i = 0; i < arr.length; i++) {
        var sum = 0
        for (let j = i; j < arr.length; j++) {
            sum += arr[j];
            max = Math.max(max, sum)
            //~ if (sum > max) max = sum;
        }
    }
    return max
}

var start = performance.now()
r = bruteForce(arr)
var end = performance.now()
console.log(end - start, 'ms', 'N=', N, 'result=', r)
//~ console.log(arr.slice(0, 10))

Code for Cython (or Python), enriched with a few type-hints:

import cython
from time import perf_counter as clock
from random import randint

N = 10000
arr = [randint(-1000,1000) for i in range(N)]

def bruteForce(arr):
  l: cython.int = len(arr)
  assert l <= 10000
  a: cython.int[10000] = arr  # copies mem from Python array
  max: cython.int = 0
  i: cython.int = 0
  while i < l:
    sum: cython.int = 0
    j: cython.int = i
    while j < l:
      sum += a[j]
      if sum > max:
        max = sum
      j += 1
    i += 1
  return max

start = clock()
r = bruteForce(arr)
end = clock()
print((end - start) * 1000, 'ms', 'N=', N, 'result=', r)
##print(arr[:10])

(Done on a slow notebook)

Sign up to request clarification or add additional context in comments.

3 Comments

Py took 2825.7724170107394 ms N= 10000 result= 71565, JS took 39.68283399939537 ms N= 10000 result= 49005
Here are my results on virtual machine: ~# node --version v10.19.0 ~# python3 --version Python 3.8.10 ~# python3 test.py 11107.16739995405 ms N= 10000 result= 81061 ~# node test.js 249.11676907539368 'ms' 'N=' 10000 'result=' 137303
Nobody uses PyPi because of the implementation differences mean it is not compatible 100%.
2

I also examined this, with JS and Python loop and pandas, JS is far better than Python looping and pandas.

My code:

JS:

// Create a large dataset
const NUM_RECORDS = 1000*10000
const people = Array.from({ length: NUM_RECORDS }, (_, i) => ({ name: `Person ${i}`, age: i % 100, gender: i % 2 === 0 ? 'male' : 'female' }));

// Define filter parameters
const ageThreshold = 35;
const gender = 'male';

// JavaScript filter method
const jsStartTime = Date.now();
const filteredPeopleJS = people.filter(person => person.age > ageThreshold && person.gender === gender);
const jsEndTime = Date.now();
const jsTimeTaken = (jsEndTime - jsStartTime) / 1000; // Convert milliseconds to seconds

console.log("JavaScript filter method time:", jsTimeTaken, "seconds");

Python code is:

import pandas as pd
import numpy as np
import time


NUM_RECORDS = 1000 * 10000
people = [{'name': f'Person {i}', 'age': i % 100, 'gender': 'male' if i % 2 == 0 else 'female'} for i in range(NUM_RECORDS)]
df = pd.DataFrame(people)


age_threshold = 35
gender = 'male'


python_start_time = time.time()
filtered_people_python = list(filter(lambda person: person['age'] > age_threshold and person['gender'] == gender, people))
python_end_time = time.time()
python_time_taken = python_end_time - python_start_time

pandas_start_time = time.time()
filtered_people_pandas = df[(df['age'] > age_threshold) & (df['gender'] == gender)]
pandas_end_time = time.time()
pandas_time_taken = pandas_end_time - pandas_start_time

print("Python filter time:", python_time_taken)
print("Pandas time:", pandas_time_taken)

RESULTS:
JavaScript filter method time: 0.121 seconds,
Python filter time: 0.7254292964935303,
Pandas time: 0.4761631488800049

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.