5. Python и real-time
Ограничения:
• Global Interpreter Lock
• Невысокая скорость выполнения вычислений
• Активное использование malloc
• Сборщик мусора
Преимущества:
• Простота проектирования
• Лёгкое межпроцессное взаимодействие
• Отсутствие JIT
• Низкоуровневые интерфейсы
6. Как написать real-time код?
• Асинхронность • Модули:
– (шаблон Reactor) – threading
• Гранулярность – multiprocessing
• Управление памятью – сtypes
• Расчёт penalty • Использование cython
Не заставляйте ваших клиентов ждать!
8. Асинхронность
from twisted.internet import reactor
from twisted.internet import task
def routine_1():
print ("Routine 1")
Работает
def routine_2(): в 2 и 3 :)
print ("Routine 2")
t1 = task.LoopingCall(routine_1)
t1.start(0)
t2 = task.LoopingCall(routine_2)
t2.start(0)
Не создаётся
reactor.run( ) конкурирующий
контекст потока
9. Гранулярность
• Обработка данных отдельно от подсистемы
взаимодействия
• Минимальная подготовка к ответу
• Отложенные результаты (deferreds)
10. Гранулярность
from threading import Thread, Lock
from datetime import datetime
lock = Lock()
counter = 0
def worker(tiny):
global counter
with lock:
counter += 1
id = counter Освобождение
r = range(1000000) ресурсов
if not tiny:
yield [id, sum(r)]
else:
result = [id, None]
yield result
s = 0
for x in r:
s += x
if x % 100: Ресурсоёмкая работа не
yield
result[1] = s
должна блокировать
программу
11. Управление памятью
• Выделение памяти создаёт
непредсказуемую latency
• Создавайте объекты заранее (пул)
• Используйте объекты повторно
(контейнеры)
12. Управление памятью Добавление
с поиском
class Stack(object): Эффективность
O(1)
def __init__(self, size):
self.index = -1
self.storage = [None] * size
def put(self, value):
try:
self.index += 1
self.storage[self.index] = value
except IndexError:
self.index -= 1
raise
def pop(self):
try:
self.index -= 1
result = self.storage[self.index]
self.storage[self.index] = None
return result
except IndexError:
self.index += 1
Отказ от выделения памяти
raise сокращает время выполнения
13. Расчёт penalty
• Ставьте паузы в потоках, когда нет задач
• Увеличивайте паузу после каждого «отбоя»
• Установите лимит ожидания
14. Управление памятью
from threading import Thread
from Queue import Queue, Empty
from time import sleep
class SmartThread(Thread):
def __init__(self, penalty=0):
super(SmartThread, self).__init__()
self.daemon = True
self.penalty = penalty
self.step = penalty / 10
self.sleep = 0
self.queue = Queue()
def run(self, penalty=False):
while True:
try:
d = self.queue.get_nowait()
self.wait
except Empty:
if self.penalty:
if self.sleep < self.penalty:
self.sleep += self.step
sleep(self.sleep)
Процессор не греется!
Ожидание в момент простоя