12. Parallel processing

12.1. Motivation and plan

Parallel processing is key to high performance computing, but it is important for every hacker to know how programs do this kind of processing.

12.2. Concepts

CPU

A physical CPU chip.

core

One of several logical CPUs inside a single physical CPU.

process

An separate flow of execution with its own memory and instructions. Separate processes appear to execute at the same time, and sometimes they do (when you have multiple cores).

thread

A light-weight process which shares data with other threads in the same process.

multiprocessing

multithreading

race condition

With multithreading and multiprocessing you could have one execution threads trying to access memory while another is modifying it.

synchronization

The collection of techniques that help resolve race conditions.

mutex

A “mutual exclusion” object which allows programs to decide who is currently using a resource.

12.3. Python multithreading library

Listing 12.3.1 Simplest multithreading program.
#! /usr/bin/env python3

import threading


def main():
    threads = []
    for i in range(5):
        t = threading.Thread(target=worker)
        threads.append(t)
        t.start()

def worker():
    """thread worker function"""
    print('Worker')
    return

main()
Listing 12.3.2 Multithreading program with a bit more.
#! /usr/bin/env python3
import threading

def main():
    threads = []
    for i in range(5):
        t = threading.Thread(target=worker, args=(i,))
        threads.append(t)
        t.start()

def worker(num):
    """thread worker function"""
    print('Worker: %s' % num)
    return

main()
Listing 12.3.3 Multithreading program with actual work.
#! /usr/bin/env python3

import threading
import time
import random

def main():
    service_thread = threading.Thread(name='my_service', target=my_service)
    worker_list = []
    print('creating the threads')
    for i in range(5):
        w = threading.Thread(name='worker_' + str(i), target=worker)
        worker_list.append(w)

    print('starting the service and worker threads')
    service_thread.start()
    for i in range(5):
        worker_list[i].start()

    for i in range(5):
        worker_list[i].join()
    service_thread.join()
    print('** main program is at an end **')

def worker():
    """sleep a random amount of time and exit"""
    myname = threading.currentThread().getName()
    sleep_time = random.randint(0, 10)
    print(myname, 'Starting')
    time.sleep(sleep_time)
    print(myname, 'Exiting after', sleep_time, 'seconds')

def my_service():
    """long running service"""
    myname = threading.currentThread().getName()
    sleep_time = 20
    print(myname, 'Starting')
    time.sleep(sleep_time)
    print(myname, 'Exiting after', sleep_time, 'seconds')

main()