Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ЛР-7 / ЯП №7

.pdf
Скачиваний:
1
Добавлен:
06.06.2026
Размер:
543.65 Кб
Скачать

Министерство науки и высшего образования Российской Федерации Федеральное государственное автономное образовательное учреждение высшего образования

ТОМСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ СИСТЕМ УПРАВЛЕНИЯ И РАДИОЭЛЕКТРОНИКИ (ТУСУР) Кафедра безопасности информационных систем (БИС)

ФУНКЦИОНАЛЬНЫЙ СТИЛЬ ПРОГРАММИРОВАНИЯ. ПАРАЛЛЕЛЬНОЕ ПРОГРАММИРОВАНИЕ

Отчет по лабораторной работе №7

по дисциплине «Языки программирования»

Студент гр.

_______

_______

Принял:

Доцент каф. КИБЭВС,

д.т.н., доцент

_______ Романов А. С.

_______

Томск 2026

 

Оглавление

Введение...................................................................................................................

3

Ход работы...............................................................................................................

4

Заключение ..............................................................................................................

5

Приложение А .........................................................................................................

6

2

Введение

Цель работы – реализовать систему, где:

1.Данные хранятся в неизменяемых структурах.

2.Вся обработка идет через цепочку чистых функций и лямбд с помощьюя

Map/Filter/Reduce.

3. Ошибки и пустые данные обрабатываются через кастомную монаду

Maybe / Either.

4.Настройки и фильтры задаются через каррирование.

5.Сложные вложенные структуры обходятся с помощью рекурсии.

6.Вычисления распараллеливаются через чистый Map/Reduce. Нарезка данных, параллельный маппинг воркерами на уровне процессов ОС и финальная свертка результатов должны выполняться без риска взаимных блокировок благодаря полной чистоте функций. Код написан на ЯП Python для

19 варианта.

3

Ход работы

В ходе работы была реализована система с помощью кода (приложение А), по заданной структуре, проведен демонстрационный вывод (рисунок 1.1).

Рисунок 1.1 – Демонстрационный вывод

4

Заключение

В ходе работы была реализована система, удовлетворяющая всем пунктам структуры для ИЗ по вариантом 19, на ЯП Python.

5

Приложение А

(обязательное)

Код реализации системы

from dataclasses import dataclass, replace

from typing import Callable, List, Tuple, Optional, Any, NamedTuple from functools import reduce

from multiprocessing import Pool, cpu_count import random

# 1. ИММУТАБЕЛЬНЫЕ СТРУКТУРЫ ДАННЫХ

@dataclass(frozen=True)

class GeoCoord: #неизменяемые географические координаты фонаря lat: float

lon: float

@dataclass(frozen=True)

class SunSchedule: #неизменяемый график восхода/захода солнца sunrise_hour: float

sunset_hour: float

@dataclass(frozen=True)

class LampConfig: #неизменяемая конфигурация фонаря lamp_id: str

location: GeoCoord max_lumens: int power_watts: float sun_schedule: SunSchedule

@dataclass(frozen=True)

class SensorReading: #неизменяемое показание датчика lamp_id: str

timestamp: float lux: float is_raining: bool

@dataclass(frozen=True)

class LampState: #неизменяемое состояние фонаря (результат вычислений) lamp_id: str

brightness_percent: float power_consumption: float is_emergency: bool

# 2. МОНАДА MAYBE (обработка ошибок)

class Maybe: #монада Maybe для безопасной работы с отсутствующими данными def __init__(self, value: Any):

self._value = value

def bind(self, func: Callable[[Any], 'Maybe']) -> 'Maybe': #монадическое связывание

6

(flatMap)

if self._value is None: return Maybe(None)

return func(self._value)

def map(self, func: Callable[[Any], Any]) -> 'Maybe': #функтор map if self._value is None:

return Maybe(None) try:

return Maybe(func(self._value)) except Exception:

return Maybe(None)

def get_or_else(self, default: Any) -> Any:

return self._value if self._value is not None else default

def is_nothing(self) -> bool: return self._value is None

def is_just(self) -> bool:

return self._value is not None

def __repr__(self):

return f"Just({self._value})" if self.is_just() else "Nothing"

# 3. ЧИСТЫЕ ФУНКЦИИ (глобальные для сериализации в multiprocessing) def calculate_brightness(lux: float, is_raining: bool, sunset_hour: float,

timestamp: float, max_lumens: int) -> float: #чистая функция: вычисление процента яркости светодиодной лампы в зависимости от уровня естественного света.

if lux < 0: lux = 0

base_brightness = max(0, min(100, 100 - (lux / 10))) rain_multiplier = 1.3 if is_raining else 1.0 hours_after_sunset = max(0, timestamp - sunset_hour) night_boost = 1.0 + (hours_after_sunset * 0.1)

final_brightness = base_brightness * rain_multiplier * night_boost return min(100, final_brightness)

def calculate_power_consumption(brightness_percent: float, max_power: float) -> float:

#чистая функция: расчёт потребляемой мощности return (brightness_percent / 100) * max_power

#4. ЛЯМБДА-ФУНКЦИИ (фильтры) CRITICAL_DARK = 5.0

is_emergency_dark = lambda reading: reading.lux < CRITICAL_DARK is_night_time = lambda reading: reading.timestamp < 7 or reading.timestamp > 19 is_critical_post = lambda reading: reading.lux < CRITICAL_DARK

#5. ФУНКЦИЯ ВЫСШЕГО ПОРЯДКА (ФВП)

def manage_grid(lux_filter: Callable[[SensorReading], bool], dimming_strategy: Callable[[List[LampState]], List[LampState]], lamps: Tuple[LampConfig, ...],

7

readings: Tuple[SensorReading, ...]) -> List[LampState]: #ФВП: контроллер энергосбережения принимает функцию-фильтр и функцию-стратегию диммирования.

filtered_readings = list(filter(lux_filter, readings)) lamp_states = []

for reading in filtered_readings: lamp_config = next(

(l for l in lamps if l.lamp_id == reading.lamp_id), None

)

if lamp_config:

brightness = calculate_brightness( reading.lux, reading.is_raining, lamp_config.sun_schedule.sunset_hour,

reading.timestamp, lamp_config.max_lumens

)

power = calculate_power_consumption(brightness, lamp_config.power_watts) state = LampState(

lamp_id=reading.lamp_id, brightness_percent=brightness, power_consumption=power, is_emergency=reading.lux < CRITICAL_DARK

)

lamp_states.append(state)

return dimming_strategy(lamp_states)

# 6. КАРРИРОВАНИЕ (Currying)

def apply_holiday_profile(profile_name: str): #каррированная функция: фиксация праздничного режима

def with_dimming_curve(dimming_curve: str): def with_lamp_id(lamp_id: str) -> dict:

return {

"profile": profile_name, "curve": dimming_curve, "lamp": lamp_id,

"brightness_override": 80 if profile_name == "New_Year" else 100

}

return with_lamp_id return with_dimming_curve

# 7. РЕКУРСИЯ (обход вложенных структур) @dataclass(frozen=True)

class PowerLineNode: #узел электропередачи (для каскадного отключения) node_id: str

children: Tuple['PowerLineNode', ...] = () is_active: bool = True

def cascade_disconnect(node: PowerLineNode,

fault_node_id: str) -> PowerLineNode: #рекурсивная функция: каскадное отключение линий электропередачи при обнаружении короткого замыкания.

if node.node_id == fault_node_id:

return replace(node, is_active=False, children=tuple( replace(child, is_active=False) for child in node.children

))

8

new_children = tuple( cascade_disconnect(child, fault_node_id) for child in node.children

)

any_child_disabled = any(not c.is_active for c in new_children)

return replace(node, children=new_children, is_active=not any_child_disabled)

# 8. REDUCE (свёртка)

def reduce_grid_consumption(states: List[LampState]) -> dict: # Reduce: cжатие данных о потреблении всей сети фонарей в итоговую метрику.

if not states:

return {"total_kwh": 0, "avg_brightness": 0, "emergency_count": 0} total_power = reduce(lambda acc, s: acc + s.power_consumption, states, 0)

avg_brightness = reduce(lambda acc, s: acc + s.brightness_percent, states, 0) / len(states) emergency_count = reduce(lambda acc, s: acc + (1 if s.is_emergency else 0), states, 0) total_kwh = total_power / 1000

return {

"total_kwh": total_kwh, "avg_brightness": avg_brightness, "emergency_count": emergency_count,

"savings_percent": max(0, 100 - avg_brightness)

}

# 9. ПАРАЛЛЕЛЬНЫЙ MAP/REDUCE

class WorkerInput(NamedTuple): #иммутабельный вход для воркера readings: List[SensorReading]

lamps: List[LampConfig]

def process_chunk_worker(worker_input: WorkerInput) -> List[LampState]: #чистая глобальная функция-маппер для воркера.

results = []

lamps_dict = {l.lamp_id: l for l in worker_input.lamps} for reading in worker_input.readings:

lamp = lamps_dict.get(reading.lamp_id) if lamp:

brightness = calculate_brightness( reading.lux, reading.is_raining, lamp.sun_schedule.sunset_hour, reading.timestamp, lamp.max_lumens

)

power = calculate_power_consumption(brightness, lamp.power_watts) results.append(LampState(

lamp_id=reading.lamp_id, brightness_percent=brightness, power_consumption=power, is_emergency=reading.lux < CRITICAL_DARK

))

return results

def parallel_process_lamps(lamps: Tuple[LampConfig, ...], readings: Tuple[SensorReading, ...],

num_workers: Optional[int] = None) -> List[LampState]: #параллельная

9

обработка через чистый Map/Reduce if num_workers is None:

num_workers = min(cpu_count(), 4)

readings_list = list(readings) lamps_list = list(lamps)

chunk_size = max(1, len(readings_list) // num_workers) chunks = [

WorkerInput(readings_list[i:i + chunk_size], lamps_list) for i in range(0, len(readings_list), chunk_size)

]

with Pool(num_workers) as pool:

mapped_results = pool.map(process_chunk_worker, chunks)

all_states = reduce(lambda acc, chunk: acc + chunk, mapped_results, []) return all_states

# ГЕНЕРАЦИЯ ТЕСТОВЫХ ДАННЫХ

def generate_test_data(num_lamps: int = 100) -> Tuple[Tuple[LampConfig, ...], Tuple[SensorReading, ...]]: #чистая функция генерации тестовых данных

random.seed(42) lamps = tuple(

LampConfig( f"lamp_{i:03d}",

GeoCoord(56.0 + i * 0.001, 84.0 + i * 0.001), 5000 + (i % 3) * 1000,

50.0 + (i % 3) * 10,

SunSchedule(6.0 + (i % 2) * 0.5, 19.0 + (i % 2) * 0.5)

)

for i in range(num_lamps)

)

readings = tuple( SensorReading(

f"lamp_{i:03d}",

22.0 if i % 3 == 0 else 14.0, random.uniform(0.5, 200.0), random.choice([True, False])

)

for i in range(num_lamps)

)

return lamps, readings

# ДЕМОНСТРАЦИЯ РАБОТЫ СИСТЕМЫ def run_demo():

#базовые данные lamps = (

LampConfig("lamp_001", GeoCoord(56.49, 84.98), 5000, 50.0, SunSchedule(6.5, 19.5)), LampConfig("lamp_002", GeoCoord(56.50, 84.99), 6000, 60.0, SunSchedule(6.5, 19.5)), LampConfig("lamp_003", GeoCoord(56.51, 85.00), 4500, 45.0, SunSchedule(6.5, 19.5)), LampConfig("lamp_004", GeoCoord(56.52, 85.01), 7000, 70.0, SunSchedule(6.5, 19.5)),

10

Соседние файлы в папке ЛР-7