Benchmarking Dart vs. Python and JavaScript: Results and Insights

Benchmarking Dart. Python and JavaScript offers valuable insights into their strengths and weaknesses, particularly in handling CPU-bound tasks, I/O operations, and memory-intensive processes.
Benchmarking Dart vs. Python and JavaScript: Results and Insights
benchmarking dart

Choosing the right programming language for a project can significantly impact performance, scalability, and development efficiency. Dart, Python, and JavaScript are three popular languages, each excelling in distinct domains. Dart, known for its speed and modern design, powers Flutter and server-side applications. Python, celebrated for its simplicity and extensive ecosystem, is a go-to language for data science, scripting, and backend development. JavaScript, the cornerstone of web development, thrives in event-driven and asynchronous tasks.

Benchmarking these languages offers valuable insights into their strengths and weaknesses, particularly in handling CPU-bound tasks, I/O operations, and memory-intensive processes. This study aims to compare the performance of Dart, Python, and JavaScript under similar conditions to help developers make informed decisions based on specific use cases. By exploring execution times, resource usage, and runtime efficiencies, this benchmarking exercise sheds light on which language is best suited for different scenarios.

Table of Contents

Benchmarking Setup

To ensure a fair and consistent comparison between Dart, Python, and JavaScript, we carefully designed the benchmarking setup. This section outlines the tasks selected for benchmarking, the hardware and software environment used, and the methodology for timing and measuring performance.

Tasks for Benchmarking

The benchmarking tasks were chosen to reflect common real-world scenarios and test different aspects of language performance. These tasks include:

  1. CPU-bound Task:
    Numerical computations, such as summing a large range of numbers.
  2. I/O-bound Task:
    Reading and writing large files.
  3. Memory-intensive Task:
    Sorting large datasets.

Benchmarking Environment

The benchmarks were executed on the same machine to maintain consistency and reduce variability caused by hardware differences. The specifications are as follows:

  • Hardware:
    • CPU: Intel Core i5-1135G7 (4 cores, 8 threads, 2.4 GHz base clock).
    • RAM: 16 GB DDR4.
    • Storage: SSD.
  • Software:
    • Dart: Stable version with JIT (Just-In-Time) compilation.
    • Python: Python 3.x (standard CPython).
    • JavaScript: Node.js with the V8 engine.

Execution Modes

Each language was run in its optimized environment to showcase its best potential:

  • Dart: Compiled in release mode using JIT for optimal performance:
dart run
  • Python: Executed with CPython interpreter better performance comparison:
python <filename>
  • JavaScript: Executed using Node.js for its V8 engine optimizations:
node <filename>

Timing and Measurement

To measure performance accurately, we used language-specific tools and techniques:

  • Dart: Measured execution time with Stopwatch in milliseconds.
  • Python: Used timeit module for precise timing or manual time tracking with time.
  • JavaScript: Leveraged console.time and console.timeEnd for millisecond-accurate timing.

Each task was executed multiple times to account for variations in performance, and the average execution time was recorded for analysis.

Benchmarking Dart vs Python and JavaScript

To achieve a meaningful comparison of Dart, Python, and JavaScript, we employed a structured approach to benchmarking. This methodology ensures fairness, consistency, and reliability in measuring the performance of each language across different tasks.

1. CPU-Bound Task: Summing Integers

Dart:

void main() {
  final stopwatch = Stopwatch()..start();
  
  int sum = 0;
  for (int i = 1; i <= 10000000; i++) {
    sum += i;
  }
  
  stopwatch.stop();
  print('Dart: Sum calculated in ${stopwatch.elapsedMilliseconds} ms');
}

The stopwatch is an instance of the Stopwatch class which is used to measure the time of exectution. The ..start() via the casacading operator allows the stopwatch object to begin recording time immediately after it is created.

A loop is executed to sum numbets from 1 to 10,000,000. After the execution of the loop, the stopwatch.stop() method is called to stop recording time. The total time of code execution in milliseconds is printed out on the terminal with the stopwatch.elapsedMilliseconds attribute.

Python:

import time

start = time.time()

sum = 0
for i in range(1, 10000001):
    sum += i

end = time.time()
print(f'Python: Sum calculated in {(end - start) * 1000:.2f} ms')

The time module in the Python standard library is used to keep track of execution time. The start variable defines the time in seconds when the Python code is executed. As seen in the Dart version a loop is executed suming up numbets from 1 to 10,000,000. After the loop is completed the end variable captures the time.

On the terminal, the time difference between start and end is deducted and the execution time is rendered in milliseconds.

JavaScript:

console.time('JavaScript');

let sum = 0;
for (let i = 1; i <= 10000000; i++) {
  sum += i;
}

console.timeEnd('JavaScript');

The JavaScript implementation follows a similar pattern like those of Dart and Python. console.time() function captures the time the code execution begins. The loop is executed and when it is completed, the console.timeEnd() records the entire time the program ran.

The execution time of the program is also relayed in milliseconds.

N.B., The methodology for capturing execution time of each programming language remains the same across I/O and memory-intensive operations.

2. I/O-Bound Task: File Read/Write

Dart:

import 'dart:io';

void main() async {
  final stopwatch = Stopwatch()..start();

  final file = File('test.txt');
  await file.writeAsString('Dart I/O Benchmark\n' * 100000);
  final content = await file.readAsString();

  stopwatch.stop();
  print('Dart: File I/O completed in ${stopwatch.elapsedMilliseconds} ms');
}

Python:

import time

start = time.time()

with open('test.txt', 'w') as f:
    f.write('Python I/O Benchmark\n' * 100000)
with open('test.txt', 'r') as f:
    content = f.read()

end = time.time()
print(f'Python: File I/O completed in {(end - start) * 1000:.2f} ms')

JavaScript:

const fs = require('fs');
console.time('JavaScript');

fs.writeFileSync('test.txt', 'JavaScript I/O Benchmark\n'.repeat(100000));
const content = fs.readFileSync('test.txt', 'utf8');

console.timeEnd('JavaScript');

3. Memory-Intensive Task: Sorting a Large Array

Dart:

import 'dart:math';

void main() {
  final random = Random();
  final stopwatch = Stopwatch()..start();

  final numbers = List.generate(1000000, (_) => random.nextInt(1000000));
  numbers.sort();

  stopwatch.stop();
  print('Dart: Sorting completed in ${stopwatch.elapsedMilliseconds} ms');
}

Python:

import time
import random

numbers = [random.randint(0, 1000000) for _ in range(1000000)]
start = time.time()

numbers.sort()

end = time.time()
print(f'Python: Sorting completed in {(end - start) * 1000:.2f} ms')

JavaScript:

console.time('JavaScript');

const numbers = Array.from({ length: 1000000 }, () => Math.floor(Math.random() * 1000000));
numbers.sort((a, b) => a - b);

console.timeEnd('JavaScript');

Results and Insights

The benchmarking results reveal distinct performance characteristics of Dart, Python, and JavaScript across various tasks. Below, we present the execution times for CPU-bound, I/O-bound, and memory-intensive tasks, followed by a comparative analysis of their performance.

1. CPU-Bound Task: Summing Integers

Language Execution Time (ms)
Dart 8
Python 511.28
JavaScript 13.323

Analysis:

  • Dart outperformed Python and JavaScript, showcasing its speed due to Just-In-Time (JIT) compilation.
  • JavaScript followed closely, benefiting from V8’s Just-In-Time (JIT) optimization.
  • Python lagged behind, as CPython's interpreted nature introduces overhead.

2. I/O-Bound Task: File Read/Write

Language Execution Time (ms)
Dart 28
Python 6.79
JavaScript 14.12

Analysis:

  • Dart performed competitively, leveraging its asynchronous Future and JIT compilation.
  • Python was fastest, due its simplicity and robust libraries making it a viable choice for I/O-bound tasks.
  • JavaScript was a close second, exhibited decent speed for I/O operations, thanks to its event-driven architecture and efficient handling in Node.js.

Memory-intensive Task: Sorting a Large Array

Language Execution Time (ms)
Dart 290
Python 188.89
JavaScript 326.958

Analysis:

  • Dart again demonstrated superior performance, with efficient memory management and fast sorting algorithms.
  • JavaScript came in third, showcasing the language is not the best option for memory intensive tasks even with the V8’s optimizations for handling large datasets.
  • Python was again the fastest overall, however, CPython introduces overhead in operations requiring frequent memory allocation and deallocation.

Key Observations

  • Dart is a good choice for performance-critical applications, particularly those with heavy computational or memory requirements.
  • JavaScript shines in I/O-bound workflows and asynchronous environments, such as web servers or event-driven applications.
  • Python, while slower in execution, remains unmatched for its versatility, rapid prototyping, and wide range of libraries, especially in data science and scripting.

Limitations and Challenges

While the benchmarking results provide valuable insights into the performance of Dart, Python, and JavaScript, several limitations and challenges must be considered to ensure the findings are interpreted appropriately.

1. Impact of Compiler Optimizations

  • The use of AOT (Dart) and JIT (JavaScript and PyPy) introduces compiler-level optimizations that may not reflect typical development scenarios where interpreted or unoptimized code is executed.
  • Highly optimized scenarios might overshadow the performance differences for less-critical tasks, which are more representative of everyday development needs.

2. Library and Framework Dependencies

  • Many real-world applications rely on third-party libraries or frameworks, which were not included in the benchmarks. The choice and efficiency of these tools can significantly impact the overall performance of a project.
  • For example, Python libraries like NumPy and Pandas can vastly improve performance in data manipulation tasks but were not utilized here.

3. Task Representativeness

  • The benchmarking tasks, while carefully selected, represent only a subset of real-world scenarios.
  • CPU-bound, I/O-bound, and memory-intensive operations do not cover specialized use cases like machine learning (Python), UI-heavy applications (Dart with Flutter), or front-end web development (JavaScript).
  • Language strengths tied to specific ecosystems or libraries, such as Python’s NumPy or JavaScript’s front-end frameworks, were not included in the comparison.

4. Hardware and Environment Constraints

  • All tests were conducted on a single machine (Intel Core i5-1135G7 with 16GB RAM). Results may differ significantly on hardware with different specifications, such as multi-core CPUs with higher thread counts or systems with limited memory.
  • Background processes and operating system-specific performance variations could have introduced minor inconsistencies, despite attempts to maintain a controlled environment.

Conclusion

This benchmarking study provides valuable insights into the performance of Dart, Python, and JavaScript across CPU-bound, I/O-bound, and memory-intensive tasks. Dart demonstrated superior performance in the CPU-bound task however, dropped in performance accross other tasks. JavaScript maintained good speed across CPU and I/O intensive tasks based on its event-driven architecture and efficient V8 engine. Python, showed it was a good choice for rapid development, because of its extensive library support, and flexibility in diverse domains.

Performance is only one factor in choosing a programming language. Each language has its strengths, and the right choice depends on the specific requirements of a project. Whether prioritizing raw speed, ecosystem richness, or development efficiency, understanding these trade-offs can help developers make informed decisions.

About the author
Ini Arthur

Dart Code Labs

Thoughts, stories and ideas.

Dart Code Labs

Great! You’ve successfully signed up.

Welcome back! You've successfully signed in.

You've successfully subscribed to Dart Code Labs.

Success! Check your email for magic link to sign-in.

Success! Your billing info has been updated.

Your billing was not updated.