This repository contains small example programs to see behaviour differences of multi-process and multi-thread programming model framework of various languages/runtimes.
mpmt1 series is a simple CPU load generator using multi-thread or multi-process models in various languages.
Basically, the main routine creates specified number of threads/processes, and the workers does busy loop just getting timestamp and checking if specified duration have passed.
Run programs on a server at least 2 (v)CPUs, and observe CPU usage using top command for example. (Better to refresh frequently using '-d 1'.) You would see that in some languages such as python threading model can consume only 1 CPU (100%) even if there are multiple CPUs and you specifed more than 2 contexts.
Here is the list of languages implemented so far.
- Python (thread/process)
- C (thread/process)
- Golang (goroutine(roughly thread))
- Rust (thread/process)
- Ruby (thread)
- Node.js (process/thread)
- Scala (thread)
- Lua (coroutine)
- Common Lisp (thread)
- Julia (thread)
- Perl (thread)
- Elixir (thread)
- Haskell (thread)
- Erlang (thrad)
- Java (thread)
- Pascal (thread)
- Swift (thread)
- C# (ASP.NET Core) (thread)
- Dart (thread)
- C++ (thread)
- OCaml (thread)
- Zig (thread)
- Fortran (thread/OpenMP)
- Ada(thread)
Common across languages.
$ PROGRAM [-n NUM_CONTEXT] [-d DURATION] [-m MODE]
- NUM_CONTEXT
- number of execution contexts (thread, process or so) default: 4
- DURATION
- number (in seconds) default: 5 (seconds)
- duration to generate CPU load
- MODE
- t or T : thread mode (default)
- In case of golang, 'g' (goroutine).
- p or P : process mode
- t or T : thread mode (default)
- Python3: mpmt1.py
- Uses python threading and multiprocessing.
- Notes on Python GIL(May 6, 2024)
- Python community made GIL optional as of 3.13.
- This enabled mpmt1.py thread mode running in the same parallelism with multiprocessing mode. I checked using in-house built Python 3.13.0a6 on Ubuntu 22.04 with PYTHON_GIL=0 environment variable.
- C: mpmt1.c
- Uses pthread and fork().
- Usage
make c
./mpmt1c
- Go: mpmt1.go
- Uses goroutine. No process mode.
- Usage
go run mpmt1.go
ormake go && ./mpmt1go
- Rust: rust/
- Uses nix crate for multi-process model
- Usage
cd rust
cargo run [-- [-m (t|p)] [-n NUM_CONTEXT] [-d DURATION]]
- Note
- nix crate need to enable necessary features explicitly.
- Ruby: mpmt1.rb
- Implements thread mode only. No process mode at the moment.
- Node.js: mpmt1.js
- Uses 'cluster' for process mode, 'worker_thread' for process mode.
- Tested using docker image tagged: iron-bullseye-slim (v20.14.0)
- Scala: mpmt1.scala
- Implements thread mode only. No process mode at the moment.
- In case of Ubuntu, use scala3.
- Simply
make scala
, andscala mpmt1
- Lua: mpmt1.lua
- Uses coroutine of Lua. No multi thread nor process at the moment.
- Common Lisp: mpmt1.lisp
- Implements thread mode only using 'bordeaux-threads'. No multi process at the moment. Still buggy...
- Install sbcl, and use quicklisp to install 'bordeaux-threads' and 'getopt'
- Note
- Looks like there are some my misunderstandings regarding pass-by-value or pass-by-reference in SBCL/Common Lisp. Please see the comment in 'bt:make-thread' block. If we execute this program without the '(sleep 1)', busy_worker() prints out wrong 'id'.
- Julia: mpmt1.jl
- Thread mode only at the moment.
- Note that you need to increase maximum thread number of Julia runtime by JULIA_NUM_THREADS environment variable not only -n NUM_CONTEXT.
- Perl: mpmt1.pl
- Thread mode only at the moment.
- Note: Perl interpreter-based thread runs parallelly not only concurrently different from Python, Ruby, etc.
- Elixir: mpmt1.exs
- Just worked version. Thread mode only at the moment.
- Install elixir (tested on Ubuntu 22.04 bundled 1.12.2 w/Erlang 24.2.1)
- Haskell: mpmt1.hs
- Thread mode (using forkIO) only at the moment.
- Install GHC (tested on Ubuntu 22.04 bundled 8.8.4)
- Does not implement getopt yet.
- Usage:
make haskell
$ ./mpmt1hs NUM_CONTEXT DURATION +RTS -Nn
- DURATION is in seconds, n of -N is number of platorm threads
- Erlang: mpmt1.erl
- Thread mode only at the moment.
- Install Erlang/OTP at least 24 (tested on Ubuntu 22.04 bundled 24.2.1)
- Usage:
$ erlc mpmt1.erl
$ erl -noshell -pa mpmt1.beam -s mpmt1 start NUM_CTX DURATION -s init stop
- Java: java/
- Thread mode only at the moment.
- Install at least JDK19 to see Virtual Thread feature.
- Usage
- See java/README.md for the details
- Pascal: mpmt1.pas
- Thread mode only at the moment.
- Install FreePascal (tested on Ubuntu 22.04 bundled fpc 3.2.2)
- Usage
$ fpc -o mpmt1pas mpmt1.pas
$ ./mpmt1pas NUM_CONTEXT DURATION
- Swift: mpmt1.swift
- Thread mode only at the moment.
- Tested using Swift docker image swift-5.10-RELEASE
- C# (ASP.NET Core): dotnet/
- Thread mode only at the moment.
- Tested using docker image mcr.microsoft.com/dotnet/sdk:8.0
- Usage
$ cd dotnet
$ dotnet restore
$ dotnet build
$ bin/Debug/net8.0/mpmt1 NUM_CONTEXT DURATION
- Dart: dart/
- Thread mode only at the moment.
- Tested using docker image dart:3.4.0-sdk
$ dart pub get
$ dart mpmt1.dart NUM_CONTEXT (number of threads) DURATION (in sec.)
- C++: mpmt1.cpp
- Thread mode only at the moment.
- Tested using GNU C++ 11.4.0
$ g++ -o mpmt1cpp mpmt1.cpp
$ ./mpmt1cpp NUM_CONTEXT (number of threads) DURATION (in sec.)
- OCaml: mpmt1.ml
- Thread mode only at the moment.
- Very early stage. Need to replace Thread by Domain for parallelism.
- Under development using docker image: ocaml/opam:debian-11-ocaml-5.3
- Zig: mpmt1.zig
- Thread mode only at the moment.
$ zig run mpmt1.zig -- NUM_CONTEXT DURATION (in sec.)
- Written for WASM experiment (TBD) originally.
- TODO: Create .wasm from mpmt1.zig and run it using wasmtime
- Fortran 2008: mpmt1.f08
- Thread mode via OpenMP only at the moment.
- Install libgomp1 (in case of Ubuntu)
$ gfortran mpmt1.f08 -o mpmt1f08 -fopenmp
$ ./mpmt1f08 [NUM_CONTEXT (number of threads) [DURATION (in sec.)]]
- Ada: mpmt1.adb
- Thread mode only at the moment.
- Install gnat in case of Ubuntu
$ gnatmake mpmt1.adb -o mpmt1adb
ormake ada
$ ./mpmt1adb [NUM_CONTEXT (number of threads) [DURATION (in sec.)]]
- Add some more languages. (Mojo, WebAssembly, Vala etc.)
- Update some language implementations (Erlang, etc.) to use message passing mechanism for synchronizing main/worker threads.
Measures inter thread/process communication performance.
- Python3: mpmt2.py
- A variation of mpmt1.py You can see difference of queue performance between threading and multiprocessing.
- Implement variable message size measurement.