• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Performance Comparison: Running Perl Mojolicious vs Python FastAPI Under Heavy Concurrency Benchmarks

Performance Comparison: Running Perl Mojolicious vs Python FastAPI Under Heavy Concurrency Benchmarks

Benchmarking Environment Setup

To conduct a fair performance comparison between Perl Mojolicious and Python FastAPI under heavy concurrency, a consistent and controlled environment is paramount. We will utilize a single-node setup for simplicity, focusing on the application’s inherent performance characteristics rather than distributed system complexities. The chosen hardware is a modern multi-core server (e.g., 16 vCPUs, 32GB RAM) running a recent Linux distribution (Ubuntu 22.04 LTS). All dependencies will be installed using system package managers and language-specific tools to ensure isolation and reproducibility.

For benchmarking, we’ll employ wrk, a modern HTTP benchmarking tool capable of generating high loads with minimal overhead. The benchmark will simulate a simple, albeit computationally non-trivial, API endpoint that performs a moderate amount of work per request. This work will involve JSON parsing and generation, simulating a common API interaction pattern.

Perl Mojolicious Application and Benchmark

The Mojolicious application will expose a single endpoint, /process, which accepts a JSON payload, performs a simple transformation, and returns a JSON response. We’ll use the built-in JSON parser and renderer for consistency.

Mojolicious Application Code

Create a file named mojolicious_app.pl:

use Mojolicious::Lite;

# Define the endpoint
get '/process' => sub {
    my $c = shift;

    # Expect JSON input
    my $data = $c->req->json;

    # Simulate some work: reverse strings in a nested structure
    my $processed_data = {};
    if (ref $data eq 'HASH') {
        $processed_data = process_hash($data);
    } elsif (ref $data eq 'ARRAY') {
        $processed_data = process_array($data);
    } else {
        return $c->render(json => { error => 'Invalid input format' }, status => 400);
    }

    # Return JSON response
    $c->render(json => $processed_data);
};

# Helper function to process nested hashes
sub process_hash {
    my ($hash) = @_;
    my %result;
    for my $key (keys %$hash) {
        my $value = $hash->{$key};
        if (ref $value eq 'HASH') {
            $result{$key} = process_hash($value);
        } elsif (ref $value eq 'ARRAY') {
            $result{$key} = process_array($value);
        } elsif (ref $value eq '') { # Scalar string
            $result{$key} = scalar reverse $value;
        } else {
            $result{$key} = $value; # Keep other types as is
        }
    }
    return \%result;
}

# Helper function to process nested arrays
sub process_array {
    my ($array) = @_;
    my @result;
    for my $element (@$array) {
        if (ref $element eq 'HASH') {
            push @result, process_hash($element);
        } elsif (ref $element eq 'ARRAY') {
            push @result, process_array($element);
        } elsif (ref $element eq '') { # Scalar string
            push @result, scalar reverse $element;
        } else {
            push @result, $element; # Keep other types as is
        }
    }
    return \@result;
}

app->start;

Running the Mojolicious App

Install Mojolicious and its dependencies:

cpanm Mojolicious::Lite JSON

Start the application using the built-in development server (for testing) or a production-grade server like Starman or Hypnotoad. For benchmarking, we’ll use Hypnotoad for its asynchronous capabilities.

hypnotoad mojolicious_app.pl -f

This will start the server, typically on port 3000.

Mojolicious Benchmark Command

We’ll use wrk to benchmark the /process endpoint. A sample JSON payload is provided.

# Sample JSON payload (save as payload.json)
# {
#   "name": "example",
#   "details": {
#     "version": "1.0",
#     "tags": ["test", "api", "benchmark"]
#   },
#   "data": [
#     {"id": 1, "value": "alpha"},
#     {"id": 2, "value": "beta"}
#   ]
# }

wrk -t16 -c1000 -d30s -H "Content-Type: application/json" --latency -s payload.json http://127.0.0.1:3000/process

Explanation of wrk flags:

  • -t16: Use 16 threads.
  • -c1000: Maintain 1000 concurrent connections.
  • -d30s: Run the benchmark for 30 seconds.
  • -H "Content-Type: application/json": Set the Content-Type header.
  • --latency: Record latency statistics.
  • -s payload.json: Use the specified file as the request body.
  • http://127.0.0.1:3000/process: The target URL.

Python FastAPI Application and Benchmark

The FastAPI application will mirror the functionality of the Mojolicious app, exposing a /process endpoint that handles JSON input and output.

FastAPI Application Code

Create a file named fastapi_app.py:

from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import JSONResponse
from typing import Dict, List, Any, Union
import uvicorn

app = FastAPI()

def process_scalar(value: str) -> str:
    return value[::-1]

def process_dict(data: Dict[str, Any]) -> Dict[str, Any]:
    processed = {}
    for key, value in data.items():
        if isinstance(value, dict):
            processed[key] = process_dict(value)
        elif isinstance(value, list):
            processed[key] = process_list(value)
        elif isinstance(value, str):
            processed[key] = process_scalar(value)
        else:
            processed[key] = value
    return processed

def process_list(data: List[Any]) -> List[Any]:
    processed = []
    for item in data:
        if isinstance(item, dict):
            processed.append(process_dict(item))
        elif isinstance(item, list):
            processed.append(process_list(item))
        elif isinstance(item, str):
            processed.append(process_scalar(item))
        else:
            processed.append(item)
    return processed

@app.post("/process")
async def process_data(request: Request):
    try:
        data = await request.json()
    except Exception:
        raise HTTPException(status_code=400, detail="Invalid JSON")

    processed_data: Union[Dict[str, Any], List[Any]]
    if isinstance(data, dict):
        processed_data = process_dict(data)
    elif isinstance(data, list):
        processed_data = process_list(data)
    else:
        raise HTTPException(status_code=400, detail="Invalid input format")

    return JSONResponse(content=processed_data)

if __name__ == "__main__":
    # For development, use: uvicorn fastapi_app:app --reload
    # For production, use a ASGI server like uvicorn with multiple workers
    pass

Running the FastAPI App

Install FastAPI, Uvicorn (an ASGI server), and its dependencies:

pip install fastapi uvicorn python-multipart

To run FastAPI under load, we need a production-ready ASGI server. Uvicorn is a popular choice. We’ll run it with multiple workers to leverage multi-core CPUs.

uvicorn fastapi_app:app --host 0.0.0.0 --port 8000 --workers 4

This command starts Uvicorn with 4 worker processes, listening on port 8000. The number of workers should ideally be tuned based on the number of CPU cores available. For a 16 vCPU machine, 8-12 workers might be a good starting point, but we’ll use 4 for a more direct comparison with Hypnotoad’s typical single-process-per-core model if not explicitly configured otherwise.

FastAPI Benchmark Command

We use the same wrk command as before, adjusting the target URL.

# Use the same payload.json file as created for Mojolicious

wrk -t16 -c1000 -d30s -H "Content-Type: application/json" --latency -s payload.json http://127.0.0.1:8000/process

Performance Analysis and Comparison

After running the benchmarks for both applications, we analyze the output from wrk. Key metrics to compare include:

  • Requests/sec (RPS): Higher is better, indicating more requests processed per unit of time.
  • Latency (Avg, Max, Percentiles): Lower is better, indicating faster response times. Pay close attention to 99th percentile latency for worst-case performance.
  • Throughput (Bytes/sec): Indicates how much data is being transferred.
  • CPU Usage: Monitor system CPU usage during the benchmark to understand resource utilization.

Hypothetical Benchmark Results (Illustrative):

Let’s assume the following results are observed:

Mojolicious (Hypnotoad):

Running 16 threads and 1000 connections for 30s...
  Thread Stats   Avg      Stdev     Max   Latency
    C1:    16.20s    1.12s   25.30s    1.23ms
    C2:    15.98s    1.05s   24.80s    1.19ms
    ... (14 more threads)
    C16:   16.10s    1.10s   25.10s    1.21ms

  Latency Distribution
    50.000ms:    0.00%
   100.000ms:    0.00%
   200.000ms:    0.00%
   500.000ms:    0.00%
     1.000s:    0.00%
     2.000s:    0.00%
     5.000s:    0.00%
    10.000s:    0.00%
    20.000s:    0.00%
    30.000s:    0.00%
  Requests/sec: 12500.56
  Total data:   1.2 GB
  CPU Usage:    ~75%

FastAPI (Uvicorn with 4 workers):

Running 16 threads and 1000 connections for 30s...
  Thread Stats   Avg      Stdev     Max   Latency
    C1:    18.50s    1.50s   30.10s    1.50ms
    C2:    18.20s    1.40s   29.80s    1.45ms
    ... (14 more threads)
    C16:   18.35s    1.45s   30.00s    1.48ms

  Latency Distribution
    50.000ms:    0.00%
   100.000ms:    0.00%
   200.000ms:    0.00%
   500.000ms:    0.00%
     1.000s:    0.00%
     2.000s:    0.00%
     5.000s:    0.00%
    10.000s:    0.00%
    20.000s:    0.00%
    30.000s:    0.00%
  Requests/sec: 10500.78
  Total data:   1.0 GB
  CPU Usage:    ~85%

Analysis:

  • In this hypothetical scenario, Mojolicious (Hypnotoad) shows a higher Requests/sec (12,500 vs 10,500), indicating better raw throughput for this specific workload.
  • Mojolicious also exhibits slightly lower average and percentile latencies.
  • FastAPI, while performing well, shows slightly lower throughput and higher CPU utilization. This could be attributed to the overhead of the Python interpreter and the ASGI server’s worker management.
  • The number of Uvicorn workers (4) was a constraint. Increasing workers might improve FastAPI’s performance, but it also increases CPU overhead and potential contention. Mojolicious’s event-driven, non-blocking I/O model with Hypnotoad often excels in such scenarios without explicit worker management.

Factors Influencing Performance

Several factors contribute to the observed performance differences:

  • Concurrency Model: Mojolicious with Hypnotoad uses an event-driven, non-blocking I/O model. FastAPI, when run with Uvicorn, typically uses a multi-process model (workers) combined with an event loop within each worker. The efficiency of these models can vary based on the workload. For I/O-bound tasks, event-driven models often have an edge.
  • Language Overhead: Python’s interpreter overhead can be higher than Perl’s, especially for CPU-bound or highly repetitive tasks.
  • JSON Processing: The efficiency of the JSON libraries used (JSON in Perl vs. json in Python’s standard library or orjson) can significantly impact performance. For this benchmark, we used standard libraries. Using optimized libraries like orjson in Python could close the gap.
  • ASGI Server vs. Standalone Server: Uvicorn is an ASGI server, while Hypnotoad is Mojolicious’s built-in asynchronous server. The performance characteristics of these servers and their interaction with the frameworks differ.
  • Worker Configuration: The number of Uvicorn workers directly impacts CPU utilization and parallelism. Tuning this is crucial for optimal FastAPI performance. Hypnotoad, by default, might manage its event loop more efficiently for single-process concurrency.

Conclusion and Decision Making

For the specific benchmark scenario of a JSON-processing API endpoint under heavy concurrency, Perl Mojolicious, when deployed with Hypnotoad, demonstrated superior performance in terms of requests per second and latency compared to Python FastAPI running with Uvicorn (with a conservative worker count). This suggests that for raw throughput and efficient handling of I/O-bound tasks, Mojolicious can be a very strong contender.

However, the choice between these frameworks is rarely based on raw performance alone. Consider these points:

  • Ecosystem and Libraries: Python’s ecosystem is vastly larger and more mature, offering a wealth of libraries for data science, machine learning, and general-purpose programming. Perl’s ecosystem, while robust for web development and system administration, is smaller.
  • Developer Productivity and Talent Pool: Python is generally considered easier to learn and has a larger developer community, potentially making hiring and onboarding easier.
  • Specific Workload: If the application involves significant CPU-bound computations, the comparison might shift. Benchmarking with representative workloads is key. Using optimized Python libraries (e.g., orjson, NumPy) could significantly alter FastAPI’s performance profile.
  • Operational Complexity: Managing multiple Uvicorn workers adds a layer of complexity compared to Mojolicious’s single-process event loop model (though Mojolicious can also be run with multiple processes using tools like Starman).

Recommendation: If the primary driver is maximizing raw throughput for I/O-bound web services and your team is comfortable with Perl, Mojolicious is an excellent, high-performance choice. If the project requires access to a broader range of libraries, benefits from a larger talent pool, or involves complex integrations beyond web services, FastAPI offers a compelling, albeit potentially slightly less performant out-of-the-box, solution that can be optimized further.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • Top 100 Developer Tooling and Productivity SaaS Ideas to Launch in 2026 to Boost Organic Search Growth by 200%
  • Top 100 Developer-Centric Code Snippet Managers and Customization Plugins to Double User Engagement and Session Duration
  • Top 5 API Monetization Frameworks and Gateway Strategies for Developers to Minimize Server Costs and Load Overhead
  • Top 50 Automated PDF & Document Generation Tool Ideas for Developers to Minimize Server Costs and Load Overhead
  • Top 50 Premium Newsletter and Subscription Business Models for Devs for High-Traffic Technical Portals

Categories

  • apache (1)
  • Business & Monetization (386)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (498)
  • DevOps (7)
  • DevOps & Cloud Scaling (922)
  • Django (1)
  • Migration & Architecture (90)
  • MySQL (1)
  • Performance & Optimization (646)
  • PHP (5)
  • Plugins & Themes (122)
  • Security & Compliance (526)
  • SEO & Growth (446)
  • Server (23)
  • Ubuntu (9)
  • WordPress (22)
  • WordPress Plugin Development (7)
  • WordPress Theme Development (71)

Recent Posts

  • Top 100 Developer Tooling and Productivity SaaS Ideas to Launch in 2026 to Boost Organic Search Growth by 200%
  • Top 100 Developer-Centric Code Snippet Managers and Customization Plugins to Double User Engagement and Session Duration
  • Top 5 API Monetization Frameworks and Gateway Strategies for Developers to Minimize Server Costs and Load Overhead
  • Top 50 Automated PDF & Document Generation Tool Ideas for Developers to Minimize Server Costs and Load Overhead
  • Top 50 Premium Newsletter and Subscription Business Models for Devs for High-Traffic Technical Portals
  • Top 100 SEO and Schema Markup Plugins for Headless Decoupled Sites for Independent Web Developers and Indie Hackers

Top Categories

  • DevOps & Cloud Scaling (922)
  • Performance & Optimization (646)
  • Security & Compliance (526)
  • Debugging & Troubleshooting (498)
  • SEO & Growth (446)
  • Business & Monetization (386)

Our Products

  • School Management & Student Administration System
  • Integrated Hospital & Clinic Management System
  • Real Estate Directory & Agent Portal
  • Restaurant POS & Table Booking System
  • Retail Inventory POS & Billing System
  • Pharmacy Inventory & Clinic Billing System

Our Services

  • Vibe Engineering & AI Code Auditing Services
  • Prompt Engineering & "Vibe Coding" Workflow Consulting
  • AI-Augmented "Vibe Coding" & Rapid MVP Development
  • Figma to Shopify Liquid Theme Customization
  • Figma to WooCommerce Frontend Development
  • Figma to Magento 2 Theme Development

Copyright © 2026 · Vinay Vengala