15. Конкурентност

15. Конкурентност

15. Конкурентност

27 април 2016

Въпрос 1

Кои са трите основни неща в един изпълним файл/DLL


Кода на приложението

import таблица

export таблица

Въпрос 2

Как работят компилацията и интерпретацията?


Компилацията превежда отделен файл с програмен код към машинни инструкции

Интерпретацията изпълнява кода "в реално време" без този процес на превод

Въпрос 3

Какво са статично и динамично линкване? Плюсове и минуси за всяко


Когато кодът на нужните библиотеки е в изпълнимия файл

В изпълнимия файл има единствено имена на библиотеки и функции

По-големи изпълними файлове при статично линкване

Малко по-бързо изпъленение при статично линкване

Няма споделяне на код в обща библиотека при статично линкване

Въпрос 4

Какво е JIT?


Компилация на код до междинен език (Java bytecode, MSIL)

Който после, по време на изпълнение, се компилира до машинен

Въпрос 5

Плюсове и минуси на JIT


По-бавен startup time, тъй като се налага междинния код да се транслира

Евентуално по-бързо изпълнение от чист native код по две причини:

- При дълго вървящи процеси, runtime-ът може да оптимизира hot paths

- Когато upgrade-нем хардуера и runtime-а, всички "стари" програми ще вървят по-бързо

Доста повече метаинформация, идваща от runtime-a

Благинки като garbage-collection, reflection

Ама първо

Предадените идеи за проекти са < 15

Крания срок е тази събота, не се мотайте

Писането на идеите за проекти не е лесно

Ама все пак се постарайте

Предавайте идеите си като решения на задачата

Идеите пратени по мейл не важат

ОК е да copy-paste-нете мейла си като решение на задачата

В петък

Ще имате и истинско домашно, за да не страдате.

Конкурентност

Що е то?

Когато две изчисления се случват едновременно

Когато две изчисления нямат ясно дефинирана последователност на изпълнение.

Демек…?

Паралелизъм?

Това, за което повечето хора си мислят, когато им говориш за конкурентност.

Две изчисления, които реално се изпълняват едновременно

Предполага наличието на много ядра/процесори, така че няколко задачи наистина да вървят паралелно

Наличието на конкурентност прави паралелизма възможен

Подходи

В Python

Видове нишки

Global Interpreter Lock

Един python процес винаги работи върху едно ядро

Досадно е, но уви спестява един ред други проблеми

Възможно е дори реферирането на променлива в няколко нишки едновременно да създаде проблем(защо?)

fork

Пример с fork (на C)

#include <stdio.h>

int main()
{
    printf("before\n");
    if (fork())
        printf("father\n");
    else
        printf("son\n");
    printf("both\n");
}


before
son
both
father
both

Пример с fork (на Python)

import os

print("before")
if os.fork():
    print("father")
else:
    print("son")
print("both")

В картинки

В картинки

В картинки

В картинки

В картинки

По-сложен пример с fork

import os
import time

def log(msg): print("\n* " + msg)

orders = 0
while True:
    order = input('Enter order: ')
    if not order: continue
    if order in ('q', 'x', 'quit', 'exit'): break
    pid = os.fork()
    if pid == 0:
        time.sleep(3)
        log("Order '{0}' is ready!".format(order))
        break
    else:
        log("Roger that '{0}'({1}). Please, wait.".format(order, orders))
        orders += 1

Синхронизация при fork

import os

pid = os.fork()
if pid == 0:
    os.execlp('date', 'date')
else:
    status = os.wait()
    print("Father: son has finished {0}".format(status))

можем да ползваме и сигнали import signal

Предимства и недостатъци на fork

Против:

За:

  • Стабилност
  • Синът е независим - ако омаже нещо, бащата няма да пострада

Нишки

Създаване на нова нишка

даваме функция с параметри към нея

или

  • Нишка — наследник на threading.Thread
  • Код — в метода run
  • Създаване и изпълнение на кода паралелно — метод start

Пример с нишки

import threading

def f(name):
    print("Hello from {0}".format(name))

thread = threading.Thread(target=f, args=('Bob',))
thread.start()
thread.join()

Пример с нишки(2)

import threading
import time

orders = 0

class Chef(threading.Thread):
    def __init__(self, order):
        self.order = order
        threading.Thread.__init__(self)
    def run(self):
        time.sleep(3)
        log("Order '{0}' is ready!".format(self.order))

while True:
    order = input('Enter order: ')
    if not order: continue
    if order in ('q', 'x', 'quit', 'exit'): break
    chef = Chef(order)
    chef.start()
    log("Roger that '{0}'. Please, wait in quiet desperation.".format(order))
    orders += 1

Вечерящи философи

import random, time, threading

taken = False
class Philosopher(threading.Thread):
    def __init__(self, name):
        super().__init__(); self.name = name

    def log(self, msg): print("{0}: {1}".format(self.name, msg))
    def eat(self): time.sleep(random.random())
    def ponder(self): time.sleep(random.random())

    def refresh(self):
        global taken
        self.log("Please excuse me...");
        while taken: pass;
        taken = True; self.log("--> (entered the bathroom)")
        time.sleep(random.random())
        taken = False; self.log("<-- (left the bathroom)")

    def run(self):
        while True:
            self.eat(); self.ponder(); self.refresh()

Критични секции

threading.Lock

Философите, отново

import random, time, threading

bathroom = threading.Lock()

class Philosopher(threading.Thread):
    def __init__(self, name):
        super().__init__(); self.name = name

    def log(self, msg): print("{0}: {1}".format(self.name, msg))
    def eat(self): time.sleep(random.random())
    def ponder(self): time.sleep(random.random())

    def refresh(self):
        self.log("Please excuse me...")
        bathroom.acquire(); self.log("--> (entered the bathroom)")
        time.sleep(random.random())
        bathroom.release(); self.log("<-- (left the bathroom)")

    def run(self):
        while True:
            self.eat(); self.ponder(); self.refresh()

with и обекти с acquire и release

with bathroom:
    self.log("--> (entered the bathroom)")
    time.sleep(random.random())
    self.log("<-- (left the bathroom)")

Модерно строителство, модерни ресторанти и семафори

А aко има повече от една тоалетна в сградата?

Или още по-добре

  • Ресторант с 10 човека
  • Всеки е едновременно готвач и сервитьор
  • 5 фурни

Семафори в орехова черупка

threading.Semaphore

Ресторанта на Грибоедов

import threading, random, time

ovens = threading.Semaphore(5)

class WaiterChef(threading.Thread):
    def __init__(self, name):
        super(WaiterChef, self).__init__()
        self.name = name

    def run(self):
        while True:
            print("...({0}) waiting for an oven".format(self.name))
            ovens.acquire()
            print("--> ({0}) Cooking...".format(self.name))
            time.sleep(random.random() * 10)
            ovens.release()
            print("<-- ({0}) Serving...".format(self.name))
            time.sleep(random.random() * 4)


for _ in range(0, 10):
  WaiterChef(_).start()

threading.Event

Коледа на село

threading.Condition

threading.local

multiprocessing

multiprocessing модулът

multiprocessing - пример

from multiprocessing import Process
import os

def info(title):
    print(title)
    print('module name:', __name__)
    print('parent process:', os.getppid())
    print('process id:', os.getpid())

def f(name):
    info('function f')
    print('hello', name)

if __name__ == '__main__':
    info('main line')
    p = Process(target=f, args=('bob',))
    p.start()
    p.join()

multiprocessing - пример с обща памет

from multiprocessing import Process, Value

def f(n):
    # work
    v = n.value
    for x in range(0, 30000): x=x+2
    n.value = v + 1
    # work

if __name__ == '__main__':
    num = Value('i', 0)
    processes = [Process(target=f, args=(num,)) for i in range(0, 10)]
    for p in processes:
        p.start()
    for p in processes:
        p.join()
    print(num.value)

multiprocessing - Lock

Lock - осигурява че само един процес може да го държи

from multiprocessing import Process, Value, Lock

def f(n, lock):
    # work
    lock.acquire()
    v = n.value
    for x in range(0, 30000): x=x+2
    n.value = v + 1
    lock.release()
    # work

if __name__ == '__main__':
    num = Value('i', 0)
    lock = Lock()
    processes = [Process(target=f, args=(num, lock)) for i in range(0, 10)]
    for p in processes:
        p.start()
    for p in processes:
        p.join()
    print(num.value)

multiprocessing - Manager

Позволява създаването на споделени обекти

from multiprocessing import Process, Manager

def f(d, l):
    d[1] = '1'
    d['2'] = 2
    d[0.25] = None
    l.reverse()

if __name__ == '__main__':
    manager = Manager()
    d, l = manager.dict(), manager.list(range(10))
    p = Process(target=f, args=(d, l))
    p.start()
    p.join()
    print(d, l)

{0.25: None, 1: '1', '2': 2}
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

multiprocessing - неща, за които трябва да се внимава под Windows

Въпроси?