[PYTHON] Summary of multi-process processing of script language

Overview

Impression that scalability-conscious programming and languages such as parallel / parallel processing, functional programming, and reactive programming have recently attracted attention. Therefore, I will summarize the basic writing method of multi-process processing using three types of scripting languages that are often used in Web development.

environment

language

Execution environment

Vagrantfile


config.vm.provider :virtualbox do |vb|
    vb.customize ["modifyvm", :id, "--memory", "1024", "--cpus", "4", "--ioapic", "on"]
  end

CPU confirmation command

top -d1
#Press 1 to see all CPUs

Ruby

Sample code

require "digest/md5"
require "securerandom"
require 'benchmark'

pcount = 4

def single(pcount)
    (pcount - 1).times do
        arr = []
        100000.times do
            arr << Digest::MD5.digest(SecureRandom.uuid)
        end
    end
end

def multi(pcount)
    pids = []
    (pcount - 1).times do
        #Process generation
        pids << fork do
            arr = []
            100000.times do
                arr << Digest::MD5.digest(SecureRandom.uuid)
            end
        end
    end

    Process.waitall

end

single_time = Benchmark.realtime do
    single(pcount)
end
print single_time.to_s() + "\n"

multi_time = Benchmark.realtime do
    multi(pcount)
end
print multi_time.to_s() + "\n"

CPU utilization

Single process

Cpu0  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu1  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu2  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu3  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

Multi-process

Cpu0  : 99.0%us,  1.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu1  : 99.0%us,  1.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu2  : 99.0%us,  1.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu3  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

result

--Single process: 4.066100899999924 --Multi-process: 1.2609145170000602

Python

Sample code

import multiprocessing as mp
import hashlib
import uuid
import time
import os

def create_hash(res=[]):
    print('created: ' + str(os.getpid()))
    for _ in range(100000):
        res.append(hashlib.md5(str(uuid.uuid4()).encode('utf8')).hexdigest())
    return res

def single(pcount):
    start_time = time.time()
    print('parent: ' + str(os.getpid()))
    res = []
    for _ in range(pcount):
        res = create_hash(res)
    end_time = time.time()
    print('all finished : ' + str(end_time - start_time))

def multi(pcount):
    start_time = time.time()
    print('parent: ' + str(os.getpid()))
    processes = []
    for _ in range(pcount):
        processes.append(mp.Process(target=create_hash, args=()))

    for process in processes:
        process.start()

    for process in processes:
        process.join()

    end_time = time.time()
    print('all finished : ' + str(end_time - start_time))

if __name__ == '__main__':
    pcount = 4
    single(pcount)
    multi(pcount)

CPU utilization

Simple process

Cpu0  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu1  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu2  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu3  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

Multi-process

Cpu0  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu1  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu2  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu3  : 99.0%us,  1.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

result

--Single process: 11.234153509140015 --Multi-process: 3.374380588531494

PHP

Sample code

//Parent process+Child process=4 processes
$pcount = 3;

function single($pcount) {
    $time_start = microtime(true);
    $res = [];
    echo 'parent : '.getmypid()."\n";

    foreach(range(0, $pcount - 1) as $i) {
        echo 'created : '.getmypid()."\n";

        foreach(range(0, 100000) as $ii) {
            $res[] = md5(uniqid(mt_rand(), true));
        }
    }

    $time_end = microtime(true);
    $time = $time_end - $time_start;

    echo "all finished : $time\n";
}

function multi($pcount) {
    $processes = [];
    $time_start = microtime(true);
    echo 'parent : '.getmypid()."\n";

    foreach(range(0, $pcount - 1) as $p) {
        //Here, it is divided into a parent process and a child process.
        //If the parent process successfully spawns a child process, the PID of that process_ID
        //If you fail-Get 1
        //Child process gets 0
        $pid = pcntl_fork();

        //Failed to spawn child process
        if ($pid === -1) {
            echo 'Failed process fork';
            exit;
        }

        //Processing of child processes
        if ($pid === 0) {
            $res = [];

            foreach(range(0, 100000) as $i) {
                $res[] = md5(uniqid(mt_rand(), true));
            }
            echo 'created : '.getmypid()."\n";
            exit;
        }

        //Processing of parent process
        $processes[] = $pid;
    }

    foreach($processes as $process) {
        pcntl_waitpid($process, $status);
    }

    $time_end = microtime(true);
    $time = $time_end - $time_start;

    echo "all finished : $time\n";
}

single($pcount);
multi($pcount);

CPU utilization

Single process

Cpu0  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu1  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu2  :  0.0%us,  1.0%sy,  0.0%ni, 99.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu3  :  0.0%us,  1.0%sy,  0.0%ni, 99.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

Multi-process

Cpu0  :  1.0%us,  0.0%sy,  0.0%ni, 99.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu1  : 99.0%us,  0.0%sy,  0.0%ni,  1.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu2  : 97.0%us,  1.0%sy,  0.0%ni,  2.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu3  : 96.1%us,  1.0%sy,  0.0%ni,  2.0%id,  0.0%wa,  0.0%hi,  1.0%si,  0.0%st

result

--Single process: 3.6952289085388 --Multi-process: 1.7085299491882

Summary

--There is also a multi-process method for scripting languages. --If the OS is not multi-core, the speed will not be increased even with multi-process processing (obviously). --In an environment with each number of CPU cores, the fastest processing is when the number of processes is the same as the number of CPU cores, and even if the number of processes is increased further, the speed will not be increased (rather slower). --In multi-process, memory is allocated to each process. -Considerations about Elixir and Reactive System and [Message passing that is effective for concurrency](http: // 97 things that programmers should know.com. For an architecture-aware implementation like / essay / message passing useful for concurrency), Ruby is process and Python is gevent seems to be good to use, so investigate separately. PHP has a module called pthreads, but since PHP is originally premised on single thread, it is not enough to force it to work. It seems better to choose the language of.

Recommended Posts

Summary of multi-process processing of script language
100 Amateur Language Processing Knock: Summary
[Language processing 100 knocks 2020] Summary of answer examples by Python
100 Language Processing Knock-59: Analysis of S-expressions
Natural language processing analyzer installation summary
Answers and impressions of 100 language processing knocks-Part 1
100 Language Processing Knock-91: Preparation of Analogy Data
100 Language Processing Knock-44: Visualization of Dependent Tree
Natural language processing of Yu-Gi-Oh! Card name-Yu-Gi-Oh!
Language processing 100 knocks-22: Extraction of category names
Answers and impressions of 100 language processing knocks-Part 2
100 Language Processing Knock-26: Removal of emphasized markup
Summary of library hosting pages by language
100 language processing knocks 03 ~ 05
100 language processing knocks (2020): 40
100 language processing knocks (2020): 32
100 language processing knocks (2020): 35
100 language processing knocks (2020): 47
100 language processing knocks (2020): 39
100 language processing knocks (2020): 22
100 language processing knocks (2020): 26
100 language processing knocks (2020): 34
100 Language Processing Knock (2020): 28
100 language processing knocks (2020): 29
100 language processing knocks (2020): 49
100 language processing knocks 06 ~ 09
100 language processing knocks (2020): 43
100 language processing knocks (2020): 24
100 language processing knocks (2020): 45
100 language processing knocks (2020): 10-19
100 language processing knocks (2020): 30
100 language processing knocks (2020): 00-09
100 language processing knocks (2020): 31
100 Language Processing Knock (2020): 38
100 language processing knocks (2020): 48
100 language processing knocks (2020): 41
100 language processing knocks (2020): 37
100 language processing knock 00 ~ 02
100 language processing knocks (2020): 25
100 language processing knocks (2020): 33
100 language processing knocks (2020): 27
100 language processing knocks (2020): 46
100 language processing knocks (2020): 21
100 language processing knocks (2020): 36
100 Language Processing Knock-45: Extraction of verb case patterns
100 language processing knock-75 (using scikit-learn): weight of features
Summary of pickle and unpickle processing of user-defined class
Unbearable shortness of Attention in natural language processing
100 amateur language processing knocks: 41
100 amateur language processing knocks: 71
100 language processing knock 2020 [00 ~ 39 answer]
100 amateur language processing knocks: 56
100 amateur language processing knocks: 24
100 amateur language processing knocks: 50
100 language processing knock 2020 [00-79 answer]
100 amateur language processing knocks: 59
100 amateur language processing knocks: 70
100 amateur language processing knocks: 62
100 amateur language processing knocks: 60
100 Language Processing Knock 2020 Chapter 1
100 amateur language processing knocks: 92