chernyshov_nikita_lab_6 #304
22
chernyshov_nikita_lab_2/README.md
Normal file
@ -0,0 +1,22 @@
|
||||
## Лабораторная работа №2
|
||||
|
||||
|
||||
**App 1: Программа 4 - Количество символов в именах файлов из каталога /var/data**
|
||||
|
||||
- Формирует файл /var/result/data.txt так, что каждая строка файла - количество символов в именах файлов из каталога /var/data.
|
||||
|
||||
**App 2: Программа 3 - Количество чисел в последовательности**
|
||||
|
||||
- Ищет набольшее число из файла /var/result/data.txt и сохраняет количество таких чисел из последовательности в /var/result/result.txt.
|
||||
|
||||
**Структура проекта:**
|
||||
|
||||
1. В папках app_1, app_2 лежат выполняемые файлы .py и Dockerfile с нужным кодом.
|
||||
2. В папке generator_of_data лежат выполняемые файлы для создания данных.
|
||||
3. В папке data лежат файлы, длину имен которых нужно посчитать.
|
||||
4. В папке result лежат файлы с результатами выполнения программ. data.txt - результат выполнения main.py (app_1), result.txt - результат выполнения main.py (app_2). Данные в result рассчитываются из данных data.
|
||||
5. docker-compose.yml - для определения и управления контейнерами Docker.
|
||||
|
||||
**Команда для запуска** - docker-compose up
|
||||
|
||||
**Ссылка на видео:** https://vkvideo.ru/video286865610_456239225?list=ln-Xqg7SupM1CohXsGRZK
|
20
chernyshov_nikita_lab_2/app_1/Dockerfile
Normal file
@ -0,0 +1,20 @@
|
||||
# Используем образ Python 3.9-slim как основу для нашего контейнера.
|
||||
# slim-версия образа более компактная, что делает контейнер меньше.
|
||||
FROM python:3.9-slim
|
||||
# Устанавливаем рабочую директорию в контейнере как /app.
|
||||
# Все последующие команды будут выполняться в этой директории.
|
||||
WORKDIR /app
|
||||
# Копируем файл main.py из текущей директории в директорию /app в контейнере.
|
||||
COPY . /app
|
||||
# Определяем команду, которая будет выполняться при запуске контейнера.
|
||||
# В данном случае запускается Python-скрипт main.py.
|
||||
CMD ["python", "main.py"]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
38
chernyshov_nikita_lab_2/app_1/main.py
Normal file
@ -0,0 +1,38 @@
|
||||
import os
|
||||
|
||||
def get_file_with_most_lines(directory):
|
||||
max_lines = 0
|
||||
target_file = ""
|
||||
|
||||
for filename in os.listdir(directory):
|
||||
filepath = os.path.join(directory, filename)
|
||||
if os.path.isfile(filepath):
|
||||
with open(filepath, 'r') as f:
|
||||
line_count = sum(1 for _ in f)
|
||||
if line_count > max_lines:
|
||||
max_lines = line_count
|
||||
target_file = filename
|
||||
|
||||
return target_file
|
||||
|
||||
def copy_file(src_directory, dest_directory, filename):
|
||||
src_filepath = os.path.join(src_directory, filename)
|
||||
dest_filepath = os.path.join(dest_directory, 'data.txt')
|
||||
|
||||
os.makedirs(dest_directory, exist_ok=True)
|
||||
|
||||
with open(src_filepath, 'r') as src_file:
|
||||
with open(dest_filepath, 'w') as dest_file:
|
||||
dest_file.write(src_file.read())
|
||||
|
||||
def main():
|
||||
src_directory = '/var/data'
|
||||
dest_directory = '/var/result'
|
||||
|
||||
target_file = get_file_with_most_lines(src_directory)
|
||||
if target_file:
|
||||
copy_file(src_directory, dest_directory, target_file)
|
||||
print(f"File {target_file} copied to {dest_directory}/data.txt")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
7
chernyshov_nikita_lab_2/app_2/Dockerfile
Normal file
@ -0,0 +1,7 @@
|
||||
FROM python:3.9-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY . /app
|
||||
|
||||
CMD ["python", "main.py"]
|
25
chernyshov_nikita_lab_2/app_2/main.py
Normal file
@ -0,0 +1,25 @@
|
||||
import os
|
||||
|
||||
def get_largest_number_from_file(filepath):
|
||||
with open(filepath, 'r') as f:
|
||||
numbers = [int(line.strip()) for line in f.readlines()]
|
||||
return max(numbers)
|
||||
|
||||
def save_square_of_number(number, output_filepath):
|
||||
result = number ** 2
|
||||
with open(output_filepath, 'w') as f:
|
||||
f.write(str(result))
|
||||
|
||||
def main():
|
||||
input_filepath = '/var/result/data.txt'
|
||||
output_filepath = '/var/result/result.txt'
|
||||
|
||||
if os.path.exists(input_filepath):
|
||||
largest_number = get_largest_number_from_file(input_filepath)
|
||||
save_square_of_number(largest_number, output_filepath)
|
||||
print(f"Largest number squared: {largest_number}^2 saved to {output_filepath}")
|
||||
else:
|
||||
print(f"Input file {input_filepath} not found!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
22
chernyshov_nikita_lab_2/docker-compose.yml
Normal file
@ -0,0 +1,22 @@
|
||||
version: '3'
|
||||
services:
|
||||
generator_of_data:
|
||||
build:
|
||||
context: ./generator_of_data
|
||||
volumes:
|
||||
- ./data:/var/data
|
||||
app_1:
|
||||
build:
|
||||
context: ./app_1
|
||||
volumes:
|
||||
- ./data:/var/data
|
||||
- ./result:/var/result
|
||||
depends_on:
|
||||
- generator_of_data
|
||||
app_2:
|
||||
build:
|
||||
context: ./app_2
|
||||
volumes:
|
||||
- ./result:/var/result
|
||||
depends_on:
|
||||
- app_1
|
7
chernyshov_nikita_lab_2/generator_of_data/Dockerfile
Normal file
@ -0,0 +1,7 @@
|
||||
FROM python:3.9-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY . /app
|
||||
|
||||
CMD ["python", "generate_data.py"]
|
27
chernyshov_nikita_lab_2/generator_of_data/generate_data.py
Normal file
@ -0,0 +1,27 @@
|
||||
import os
|
||||
import random
|
||||
|
||||
def generate_random_files(directory, num_files, num_lines_per_file, min_value, max_value):
|
||||
os.makedirs(directory, exist_ok=True)
|
||||
|
||||
for i in range(num_files):
|
||||
file_path = os.path.join(directory, f"file_{i + 1}.txt")
|
||||
with open(file_path, 'w') as f:
|
||||
for _ in range(num_lines_per_file):
|
||||
random_number = random.randint(min_value, max_value)
|
||||
f.write(f"{random_number}\n")
|
||||
print(f"Generated file: {file_path}")
|
||||
|
||||
def main():
|
||||
data_directory = '/var/data'
|
||||
num_files = 10
|
||||
num_lines_per_file = 12
|
||||
min_value = 1
|
||||
max_value = 100
|
||||
|
||||
generate_random_files(data_directory, num_files, num_lines_per_file, min_value, max_value)
|
||||
print(f"Generated {num_files} files in {data_directory}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
36
chernyshov_nikita_lab_3/README.md
Normal file
@ -0,0 +1,36 @@
|
||||
|
||||
## Лабораторная работа №3
|
||||
|
||||
### Цель:
|
||||
* Реализовать два микросервиса, которые взаимодействуют друг с другом через синхронный обмен сообщениями (HTTP-запросы). Для доступа к микросервисам используется шлюз Nginx, реализованный с помощью Docker Compose.
|
||||
|
||||
### Технологии:
|
||||
|
||||
* Python: Язык программирования для реализации микросервисов.
|
||||
* Flask: Фреймворк Python для создания веб-приложений, использован для создания REST API микросервисов.
|
||||
* requests: Библиотека Python для отправки HTTP-запросов, использован для синхронного обмена сообщениями между микросервисами.
|
||||
* flask_cors: Расширение Flask, которое позволяет микросервисам получать доступ к данным из других доменов.
|
||||
* Docker: Технология контейнеризации для упаковки и запуска микросервисов.
|
||||
* Docker Compose: Инструмент для определения и управления многоконтейнерными приложениями, использован для запуска микросервисов и шлюза Nginx.
|
||||
* Nginx: Сетевой прокси-сервер, использован как шлюз для доступа к микросервисам.
|
||||
|
||||
### Функциональность:
|
||||
|
||||
#### Микросервис games-service:
|
||||
* Реализует CRUD операции для игр (GET, POST, PUT, DELETE).
|
||||
* Сохраняет данные о играх в памяти (в словаре games).
|
||||
* Получает информацию о жанре из микросервиса genres-service через HTTP-запрос.
|
||||
* Включает информацию о жанре в ответ JSON для игры.
|
||||
#### Микросервис genres-service:
|
||||
* Реализует CRUD операции для жанров (GET, POST, PUT, DELETE).
|
||||
* Сохраняет данные о жанре в памяти (в словаре genres).
|
||||
#### Шлюз Nginx:
|
||||
* Перенаправляет HTTP-запросы на соответствующие микросервисы.
|
||||
* Предоставляет единую точку входа для доступа к микросервисам.
|
||||
|
||||
### Запуск программы:
|
||||
|
||||
* Запуск команды docker-compose up --build
|
||||
|
||||
### Ссылка на видео:
|
||||
https://vkvideo.ru/video286865610_456239226?list=ln-U577n85GB3sBxUtF34
|
26
chernyshov_nikita_lab_3/docker-compose.yml
Normal file
@ -0,0 +1,26 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
games_service:
|
||||
build:
|
||||
context: ./games_service
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "5000:5000"
|
||||
|
||||
genres_service:
|
||||
build:
|
||||
context: ./genres_service
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "5001:5001"
|
||||
|
||||
nginx:
|
||||
image: nginx:latest
|
||||
volumes:
|
||||
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
|
||||
ports:
|
||||
- "80:80"
|
||||
depends_on:
|
||||
- games_service
|
||||
- genres_service
|
10
chernyshov_nikita_lab_3/games_service/Dockerfile
Normal file
@ -0,0 +1,10 @@
|
||||
FROM python:3.11
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
CMD ["python", "main.py"]
|
53
chernyshov_nikita_lab_3/games_service/main.py
Normal file
@ -0,0 +1,53 @@
|
||||
from flask import Flask, jsonify, request
|
||||
import uuid
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
games = {}
|
||||
|
||||
|
||||
@app.route('/games', methods=['GET'])
|
||||
def get_games():
|
||||
return jsonify(list(games.values()))
|
||||
|
||||
@app.route('/games/<uuid:game_uuid>', methods=['GET'])
|
||||
def get_game(game_uuid):
|
||||
game = games.get(str(game_uuid))
|
||||
if game:
|
||||
return jsonify(game)
|
||||
return jsonify({'error': 'Not found'}), 404
|
||||
|
||||
@app.route('/games', methods=['POST'])
|
||||
def create_game():
|
||||
data = request.get_json()
|
||||
game_uuid = str(uuid.uuid4())
|
||||
game = {
|
||||
'uuid': game_uuid,
|
||||
'name': data['name'],
|
||||
'developer': data['developer'],
|
||||
'genres': data.get('genres', []) # List of genre UUIDs
|
||||
}
|
||||
games[game_uuid] = game
|
||||
return jsonify(game), 201
|
||||
|
||||
@app.route('/games/<uuid:game_uuid>', methods=['PUT'])
|
||||
def update_game(game_uuid):
|
||||
game = games.get(str(game_uuid))
|
||||
if not game:
|
||||
return jsonify({'error': 'Not found'}), 404
|
||||
data = request.get_json()
|
||||
game['name'] = data['name']
|
||||
game['developer'] = data['developer']
|
||||
game['genres'] = data.get('genres', [])
|
||||
return jsonify(game)
|
||||
|
||||
@app.route('/games/<uuid:game_uuid>', methods=['DELETE'])
|
||||
def delete_game(game_uuid):
|
||||
if str(game_uuid) in games:
|
||||
del games[str(game_uuid)]
|
||||
return '', 204
|
||||
return jsonify({'error': 'Not found'}), 404
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=5000)
|
1
chernyshov_nikita_lab_3/games_service/requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
Flask
|
10
chernyshov_nikita_lab_3/genres_service/Dockerfile
Normal file
@ -0,0 +1,10 @@
|
||||
FROM python:3.11
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
CMD ["python", "main.py"]
|
51
chernyshov_nikita_lab_3/genres_service/main.py
Normal file
@ -0,0 +1,51 @@
|
||||
from flask import Flask, jsonify, request
|
||||
import uuid
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
genres = {}
|
||||
|
||||
|
||||
@app.route('/genres', methods=['GET'])
|
||||
def get_genres():
|
||||
return jsonify(list(genres.values()))
|
||||
|
||||
@app.route('/genres/<uuid:genre_uuid>', methods=['GET'])
|
||||
def get_genre(genre_uuid):
|
||||
genre = genres.get(str(genre_uuid))
|
||||
if genre:
|
||||
return jsonify(genre)
|
||||
return jsonify({'error': 'Not found'}), 404
|
||||
|
||||
@app.route('/genres', methods=['POST'])
|
||||
def create_genre():
|
||||
data = request.get_json()
|
||||
genre_uuid = str(uuid.uuid4())
|
||||
genre = {
|
||||
'uuid': genre_uuid,
|
||||
'name': data['name'],
|
||||
'description': data['description']
|
||||
}
|
||||
genres[genre_uuid] = genre
|
||||
return jsonify(genre), 201
|
||||
|
||||
@app.route('/genres/<uuid:genre_uuid>', methods=['PUT'])
|
||||
def update_genre(genre_uuid):
|
||||
genre = genres.get(str(genre_uuid))
|
||||
if not genre:
|
||||
return jsonify({'error': 'Not found'}), 404
|
||||
data = request.get_json()
|
||||
genre['name'] = data['name']
|
||||
genre['description'] = data['description']
|
||||
return jsonify(genre)
|
||||
|
||||
@app.route('/genres/<uuid:genre_uuid>', methods=['DELETE'])
|
||||
def delete_genre(genre_uuid):
|
||||
if str(genre_uuid) in genres:
|
||||
del genres[str(genre_uuid)]
|
||||
return '', 204
|
||||
return jsonify({'error': 'Not found'}), 404
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=5001)
|
1
chernyshov_nikita_lab_3/genres_service/requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
Flask
|
11
chernyshov_nikita_lab_3/nginx/nginx.conf
Normal file
@ -0,0 +1,11 @@
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
location /games {
|
||||
proxy_pass http://games_service:5000;
|
||||
}
|
||||
|
||||
location /genres {
|
||||
proxy_pass http://genres_service:5001;
|
||||
}
|
||||
}
|
30
chernyshov_nikita_lab_4/Consumer1.py
Normal file
@ -0,0 +1,30 @@
|
||||
import pika
|
||||
import time
|
||||
|
||||
|
||||
def callback(ch, method, properties, body):
|
||||
print(f'Consumer 1 получил сообщение: {body.decode()}')
|
||||
|
||||
# Время задержки по условию
|
||||
time.sleep(2)
|
||||
|
||||
print('Consumer 1 закончил обработку')
|
||||
|
||||
|
||||
def consume_events_1():
|
||||
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
|
||||
channel = connection.channel()
|
||||
|
||||
# Создание очереди
|
||||
channel.queue_declare(queue='consumer1_queue')
|
||||
# Привязка очереди
|
||||
channel.queue_bind(exchange='beauty_salon_events', queue='consumer1_queue')
|
||||
|
||||
channel.basic_consume(queue='consumer1_queue', on_message_callback=callback, auto_ack=True)
|
||||
|
||||
print('Consumer 1 начал ожидать сообщения...')
|
||||
channel.start_consuming()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
consume_events_1()
|
28
chernyshov_nikita_lab_4/Consumer2.py
Normal file
@ -0,0 +1,28 @@
|
||||
import pika
|
||||
|
||||
|
||||
def callback(ch, method, properties, body):
|
||||
print(f'Consumer 2 получил сообщение: {body.decode()}')
|
||||
|
||||
# Обработка "нон-стопом"
|
||||
print('Consumer 2 закончил обработку')
|
||||
|
||||
|
||||
def consume_events_2():
|
||||
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
|
||||
channel = connection.channel()
|
||||
|
||||
# Создание очереди
|
||||
channel.queue_declare(queue='consumer2_queue')
|
||||
|
||||
# Привязка очереди
|
||||
channel.queue_bind(exchange='beauty_salon_events', queue='consumer2_queue')
|
||||
|
||||
channel.basic_consume(queue='consumer2_queue', on_message_callback=callback, auto_ack=True)
|
||||
|
||||
print('Consumer 2 начал ожидать сообщения...')
|
||||
channel.start_consuming()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
consume_events_2()
|
28
chernyshov_nikita_lab_4/Publisher.py
Normal file
@ -0,0 +1,28 @@
|
||||
import pika
|
||||
import time
|
||||
|
||||
|
||||
def publish_events():
|
||||
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
|
||||
channel = connection.channel()
|
||||
|
||||
# Создание exchange типа fanout
|
||||
channel.exchange_declare(exchange='beauty_salon_events', exchange_type='fanout')
|
||||
|
||||
events = [
|
||||
"Test1",
|
||||
"Test2",
|
||||
"Test3",
|
||||
"Test4",
|
||||
"Test5"
|
||||
]
|
||||
|
||||
while True:
|
||||
event = events[int(time.time()) % len(events)]
|
||||
channel.basic_publish(exchange='beauty_salon_events', routing_key='', body=event)
|
||||
print(f'Отправлено: {event}')
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
publish_events()
|
56
chernyshov_nikita_lab_4/README.md
Normal file
@ -0,0 +1,56 @@
|
||||
### Лабораторная работа №4
|
||||
|
||||
#### Задание
|
||||
|
||||
1. Установить брокер сообщений RabbitMQ.
|
||||
2. Пройти уроки 1, 2 и 3 из RabbitMQ Tutorials на любом языке программирования.
|
||||
3. Продемонстрировать работу брокера сообщений.
|
||||
|
||||
#### Описание работы программы:
|
||||
|
||||
- **Класс Publisher** успешно осуществляет отправку сообщений своим клиентам.
|
||||
|
||||
- **Класс Consumer1** принимает и обрабатывает сообщения с задержкой в 3 секунды, что можно заметить на видео.
|
||||
|
||||
- **Класс Consumer2** мгновенно принимает и обрабатывает сообщения.
|
||||
|
||||
#### Уроки
|
||||
|
||||
1. lesson1
|
||||
|
||||
![lesson1.png](lesson1.png)
|
||||
|
||||
2. lesson2
|
||||
|
||||
![lesson2.png](lesson2.png)
|
||||
|
||||
3. lesson3
|
||||
|
||||
![lesson3.png](lesson3.png)
|
||||
|
||||
## Работа с RabbitMQ Management UI
|
||||
|
||||
![img1.png](img1.png)
|
||||
|
||||
## Показания очереди queue_1 при одном запущенном экземпляре Consumer_1
|
||||
|
||||
![img2.png](img2.png)
|
||||
|
||||
## Показания очереди queue_2
|
||||
|
||||
![img3.png](img3.png)
|
||||
|
||||
## Показания очереди queue_1 при двух запущенных экземплярах Consumer_1
|
||||
![img4.png](img4.png)
|
||||
|
||||
## Показания очереди queue_1 при трех запущенных экземплярах Consumer_1
|
||||
|
||||
![img5.png](img5.png)
|
||||
|
||||
## Диспетчер задач
|
||||
|
||||
![img6.png](img6.png)
|
||||
|
||||
## Видео
|
||||
|
||||
https://vkvideo.ru/video286865610_456239227?list=ln-EUw7H8FIzc8ZwX8rG7
|
BIN
chernyshov_nikita_lab_4/img1.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
chernyshov_nikita_lab_4/img2.png
Normal file
After Width: | Height: | Size: 63 KiB |
BIN
chernyshov_nikita_lab_4/img3.png
Normal file
After Width: | Height: | Size: 66 KiB |
BIN
chernyshov_nikita_lab_4/img4.png
Normal file
After Width: | Height: | Size: 72 KiB |
BIN
chernyshov_nikita_lab_4/img5.png
Normal file
After Width: | Height: | Size: 78 KiB |
BIN
chernyshov_nikita_lab_4/img6.png
Normal file
After Width: | Height: | Size: 250 KiB |
BIN
chernyshov_nikita_lab_4/lesson1.png
Normal file
After Width: | Height: | Size: 119 KiB |
25
chernyshov_nikita_lab_4/lesson1/receive.py
Normal file
@ -0,0 +1,25 @@
|
||||
import pika, sys, os
|
||||
|
||||
def main():
|
||||
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
|
||||
channel = connection.channel()
|
||||
|
||||
channel.queue_declare(queue='hello')
|
||||
|
||||
def callback(ch, method, properties, body):
|
||||
print(f" [x] Received {body}")
|
||||
|
||||
channel.basic_consume(queue='hello', on_message_callback=callback, auto_ack=True)
|
||||
|
||||
print(' [*] Waiting for messages. To exit press CTRL+C')
|
||||
channel.start_consuming()
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
except KeyboardInterrupt:
|
||||
print('Interrupted')
|
||||
try:
|
||||
sys.exit(0)
|
||||
except SystemExit:
|
||||
os._exit(0)
|
11
chernyshov_nikita_lab_4/lesson1/send.py
Normal file
@ -0,0 +1,11 @@
|
||||
import pika
|
||||
|
||||
connection = pika.BlockingConnection(
|
||||
pika.ConnectionParameters(host='localhost'))
|
||||
channel = connection.channel()
|
||||
|
||||
channel.queue_declare(queue='hello')
|
||||
|
||||
channel.basic_publish(exchange='', routing_key='hello', body='Hello World!')
|
||||
print(" [x] Sent 'Hello World!'")
|
||||
connection.close()
|
BIN
chernyshov_nikita_lab_4/lesson2.png
Normal file
After Width: | Height: | Size: 112 KiB |
19
chernyshov_nikita_lab_4/lesson2/newtask.py
Normal file
@ -0,0 +1,19 @@
|
||||
import pika
|
||||
import sys
|
||||
|
||||
connection = pika.BlockingConnection(
|
||||
pika.ConnectionParameters(host='localhost'))
|
||||
channel = connection.channel()
|
||||
|
||||
channel.queue_declare(queue='task_queue', durable=True)
|
||||
|
||||
message = ' '.join(sys.argv[1:]) or "Hello World!"
|
||||
channel.basic_publish(
|
||||
exchange='',
|
||||
routing_key='task_queue',
|
||||
body=message,
|
||||
properties=pika.BasicProperties(
|
||||
delivery_mode=pika.DeliveryMode.Persistent
|
||||
))
|
||||
print(f" [x] Sent {message}")
|
||||
connection.close()
|
23
chernyshov_nikita_lab_4/lesson2/worker.py
Normal file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env python
|
||||
import pika
|
||||
import time
|
||||
|
||||
connection = pika.BlockingConnection(
|
||||
pika.ConnectionParameters(host='localhost'))
|
||||
channel = connection.channel()
|
||||
|
||||
channel.queue_declare(queue='task_queue', durable=True)
|
||||
print(' [*] Waiting for messages. To exit press CTRL+C')
|
||||
|
||||
|
||||
def callback(ch, method, properties, body):
|
||||
print(f" [x] Received {body.decode()}")
|
||||
time.sleep(body.count(b'.'))
|
||||
print(" [x] Done")
|
||||
ch.basic_ack(delivery_tag=method.delivery_tag)
|
||||
|
||||
|
||||
channel.basic_qos(prefetch_count=1)
|
||||
channel.basic_consume(queue='task_queue', on_message_callback=callback)
|
||||
|
||||
channel.start_consuming()
|
BIN
chernyshov_nikita_lab_4/lesson3.png
Normal file
After Width: | Height: | Size: 118 KiB |
13
chernyshov_nikita_lab_4/lesson3/emitlog.py
Normal file
@ -0,0 +1,13 @@
|
||||
import pika
|
||||
import sys
|
||||
|
||||
connection = pika.BlockingConnection(
|
||||
pika.ConnectionParameters(host='localhost'))
|
||||
channel = connection.channel()
|
||||
|
||||
channel.exchange_declare(exchange='logs', exchange_type='fanout')
|
||||
|
||||
message = ' '.join(sys.argv[1:]) or "info: Hello World!"
|
||||
channel.basic_publish(exchange='logs', routing_key='', body=message)
|
||||
print(f" [x] Sent {message}")
|
||||
connection.close()
|
22
chernyshov_nikita_lab_4/lesson3/receivelogs.py
Normal file
@ -0,0 +1,22 @@
|
||||
import pika
|
||||
|
||||
connection = pika.BlockingConnection(
|
||||
pika.ConnectionParameters(host='localhost'))
|
||||
channel = connection.channel()
|
||||
|
||||
channel.exchange_declare(exchange='logs', exchange_type='fanout')
|
||||
|
||||
result = channel.queue_declare(queue='', exclusive=True)
|
||||
queue_name = result.method.queue
|
||||
|
||||
channel.queue_bind(exchange='logs', queue=queue_name)
|
||||
|
||||
print(' [*] Waiting for logs. To exit press CTRL+C')
|
||||
|
||||
def callback(ch, method, properties, body):
|
||||
print(f" [x] {body}")
|
||||
|
||||
channel.basic_consume(
|
||||
queue=queue_name, on_message_callback=callback, auto_ack=True)
|
||||
|
||||
channel.start_consuming()
|
58
chernyshov_nikita_lab_5/README.md
Normal file
@ -0,0 +1,58 @@
|
||||
# Лабораторная работа 5: Умножение матриц
|
||||
|
||||
## Описание
|
||||
|
||||
**Цель работы** – реализовать и сравнить производительность последовательного и параллельного алгоритмов умножения матриц на больших массивах данных.
|
||||
|
||||
### Задачи:
|
||||
1. Разработать последовательный алгоритм умножения матриц.
|
||||
2. Реализовать параллельный алгоритм с возможностью настройки числа потоков.
|
||||
3. Провести тестирование обоих подходов на матрицах размером 100x100, 300x300 и 500x500.
|
||||
4. Выполнить анализ производительности, изучив зависимость времени выполнения от размера матриц и количества потоков, и сформулировать выводы.
|
||||
|
||||
## Теоретическое обоснование
|
||||
|
||||
Операция умножения матриц широко применяется в задачах вычислительного характера, таких как обработка изображений, машинное обучение и физическое моделирование. Сложность умножения матриц размером
|
||||
N×N составляет O(N^3), что приводит к резкому росту времени вычислений с увеличением размера матриц. Для ускорения работы можно использовать параллельные алгоритмы, распределяющие вычисления между несколькими потоками.
|
||||
|
||||
## Реализация
|
||||
|
||||
1. **Последовательный алгоритм:** Реализован в модуле sequential.py. Алгоритм вычисляет каждый элемент результирующей матрицы поэлементно, складывая произведения соответствующих элементов строк и столбцов исходных матриц.
|
||||
|
||||
2. **Параллельный алгоритм:** Представлен в модуле parallel.py. Он использует многопоточность, разделяя вычисления на несколько потоков, где каждый поток обрабатывает определённый блок строк результирующей матрицы. Пользователь может задавать количество потоков для оптимизации производительности с учётом размера матриц и доступных ресурсов.
|
||||
|
||||
## Результаты тестирования
|
||||
|
||||
Тестирование проводилось на матрицах размером 100x100, 300x300 и 500x500 с различным числом потоков. Было проанализировано влияние количества потоков на производительность алгоритма.
|
||||
|
||||
## Скриншоты результатов
|
||||
|
||||
### Результат бенчамарка при 1 потоке:
|
||||
![img1.png](img1.png)
|
||||
|
||||
### Результат бенчамарка при 2 потоках:
|
||||
![img2.png](img2.png)
|
||||
|
||||
### Результат бенчамарка при 4 потоках:
|
||||
![img3.png](img3.png)
|
||||
|
||||
### Результат бенчамарка при 8 потоках:
|
||||
![img4.png](img4.png)
|
||||
|
||||
## Выводы
|
||||
|
||||
1. **Эффективность параллельного алгоритма**: Использование многопоточности в параллельном алгоритме показало значительное ускорение по сравнению с последовательным методом, особенно на матрицах больших размеров. Например, для матриц размером 500x500 параллельный алгоритм с 4 потоками оказался более чем вдвое быстрее последовательного.
|
||||
|
||||
2. **Влияние количества потоков**: Увеличение числа потоков сокращает время выполнения, но этот эффект ограничен. Для небольших матриц (100x100) использование более 2 потоков практически не улучшает производительность. На матрицах среднего и большого размера (300x300 и 500x500) оптимальный результат достигался при использовании 4 потоков, так как это позволяло равномерно распределить вычислительную нагрузку.
|
||||
|
||||
3. **Закономерности и ограничения**: Эффективность параллельного умножения матриц ограничена накладными расходами на управление потоками. Для небольших задач эти расходы могут нивелировать преимущества параллелизации. Однако на больших данных задача лучше масштабируется, что делает параллельный подход значительно более выгодным.
|
||||
|
||||
4. **Рекомендации по использованию**: Для работы с большими матрицами в реальных задачах рекомендуется использовать параллельные алгоритмы, подбирая оптимальное число потоков в зависимости от объёма задачи и доступных вычислительных ресурсов.
|
||||
|
||||
## Заключение
|
||||
|
||||
Выполнение лабораторной работы показало, что параллельные алгоритмы значительно ускоряют умножение матриц на больших данных. Однако для достижения максимальной эффективности важно учитывать размер задачи и оптимально выбирать количество потоков. Полученные результаты подтверждают, что параллельный подход предпочтителен для работы с крупными матрицами, тогда как для небольших задач затраты на управление потоками могут свести его преимущества на нет.
|
||||
|
||||
## Видео
|
||||
|
||||
https://vkvideo.ru/video286865610_456239228?list=ln-RciNpMoyWby0uMIZoa
|
27
chernyshov_nikita_lab_5/benchmark.py
Normal file
@ -0,0 +1,27 @@
|
||||
import time
|
||||
import random
|
||||
from matrix_multiplication.sequential import matrix_multiply_sequential
|
||||
from matrix_multiplication.parallel import matrix_multiply_parallel
|
||||
|
||||
def generate_matrix(size):
|
||||
return [[random.randint(0, 10) for _ in range(size)] for _ in range(size)]
|
||||
|
||||
def benchmark(matrix_size, num_threads):
|
||||
A = generate_matrix(matrix_size)
|
||||
B = generate_matrix(matrix_size)
|
||||
|
||||
start = time.time()
|
||||
matrix_multiply_sequential(A, B)
|
||||
sequential_time = time.time() - start
|
||||
|
||||
start = time.time()
|
||||
matrix_multiply_parallel(A, B, num_threads)
|
||||
parallel_time = time.time() - start
|
||||
|
||||
print(f"Размер матрицы: {matrix_size}x{matrix_size}")
|
||||
print(f"Последовательное время: {sequential_time:.5f} сек")
|
||||
print(f"Параллельное время ({num_threads} потоков): {parallel_time:.5f} сек")
|
||||
|
||||
if __name__ == "__main__":
|
||||
for size in [100, 300, 500]:
|
||||
benchmark(size, num_threads=8)
|
BIN
chernyshov_nikita_lab_5/img1.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
chernyshov_nikita_lab_5/img2.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
chernyshov_nikita_lab_5/img3.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
chernyshov_nikita_lab_5/img4.png
Normal file
After Width: | Height: | Size: 19 KiB |
21
chernyshov_nikita_lab_5/matrix_multiplication/parallel.py
Normal file
@ -0,0 +1,21 @@
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
def matrix_multiply_parallel(A, B, num_threads=1):
|
||||
n = len(A)
|
||||
result = [[0] * n for _ in range(n)]
|
||||
|
||||
def worker(start, end):
|
||||
for i in range(start, end):
|
||||
for j in range(n):
|
||||
result[i][j] = sum(A[i][k] * B[k][j] for k in range(n))
|
||||
|
||||
chunk_size = n // num_threads
|
||||
with ThreadPoolExecutor(max_workers=num_threads) as executor:
|
||||
futures = [
|
||||
executor.submit(worker, i * chunk_size, (i + 1) * chunk_size)
|
||||
for i in range(num_threads)
|
||||
]
|
||||
for future in futures:
|
||||
future.result()
|
||||
|
||||
return result
|
@ -0,0 +1,9 @@
|
||||
def matrix_multiply_sequential(A, B):
|
||||
n = len(A)
|
||||
result = [[0] * n for _ in range(n)]
|
||||
|
||||
for i in range(n):
|
||||
for j in range(n):
|
||||
result[i][j] = sum(A[i][k] * B[k][j] for k in range(n))
|
||||
|
||||
return result
|
36
chernyshov_nikita_lab_6/README.md
Normal file
@ -0,0 +1,36 @@
|
||||
# Лабораторная работа 6: Определение детерминанта матрицы с помощью параллельных вычислений
|
||||
|
||||
## Описание
|
||||
|
||||
В лабраторной работе программа вычисляет определитель матрицы двумя способами: параллельным методом с использованием нескольких процессов и последовательным методом, а также сравнивает их производительность. Функция determinant_block вычисляет детерминант переданного блока матрицы с помощью функции np.linalg.det из библиотеки NumPy. Функция determinant_parallel разделяет исходную матрицу на блоки (строго по строкам и столбцам) в зависимости от количества процессов, заданного аргументом num_processes. После этого каждый блок обрабатывается отдельным процессом в пуле процессов (Pool), и вычисленные детерминанты блоков перемножаются, чтобы получить общий детерминант матрицы. Функция benchmark генерирует случайную квадратную матрицу заданного размера, измеряет время выполнения параллельного и последовательного вычисления детерминанта, а затем выводит результаты. Основная часть программы запускается, если файл выполняется напрямую. Используется модуль argparse для получения аргумента командной строки --processes, который задает количество процессов для параллельного вычисления (по умолчанию 4). В цикле for функция benchmark выполняется для матриц размеров 100x100, 300x300 и 500x500, сравнивая производительность последовательного и параллельного подходов.
|
||||
|
||||
## Результаты
|
||||
|
||||
В процессе тестирования были получены следующие результаты:
|
||||
|
||||
### Скриншоты результатов
|
||||
|
||||
#### Результат бенчамарка при 1 процессе:
|
||||
![img1.png](img1.png)
|
||||
|
||||
#### Результат бенчамарка при 2 процессах:
|
||||
![img2.png](img2.png)
|
||||
|
||||
#### Результат бенчамарка при 3 процессах:
|
||||
![img3.png](img3.png)
|
||||
|
||||
#### Результат бенчамарка при 4 процессах:
|
||||
![img4.png](img4.png)
|
||||
|
||||
|
||||
|
||||
## Выводы
|
||||
|
||||
1. **Производительность**: Для небольших матриц (например, 100x100) параллельное вычисление демонстрирует замедление по сравнению с последовательным методом из-за накладных расходов на создание и управление процессами.
|
||||
|
||||
2. **Эффективность**: С увеличением размера матриц (300x300 и 500x500) время выполнения параллельного алгоритма также растёт, что свидетельствует о снижении его эффективности при использовании большего числа процессов. В некоторых тестах, например, для матрицы 500x500 при использовании 3 и 4 процессов, параллельный алгоритм оказался медленнее последовательного.
|
||||
|
||||
|
||||
|
||||
## Ссылка на видео
|
||||
https://vkvideo.ru/video286865610_456239229?list=ln-59QwPscwM3KZRLxg1E
|
50
chernyshov_nikita_lab_6/application.py
Normal file
@ -0,0 +1,50 @@
|
||||
import numpy as np
|
||||
from multiprocessing import Pool
|
||||
import time
|
||||
import argparse
|
||||
|
||||
|
||||
def determinant_block(matrix_block):
|
||||
return np.linalg.det(matrix_block)
|
||||
|
||||
|
||||
def determinant_parallel(matrix, num_processes):
|
||||
size = matrix.shape[0]
|
||||
step = size // num_processes
|
||||
|
||||
blocks = []
|
||||
for i in range(num_processes):
|
||||
start_row = i * step
|
||||
end_row = start_row + step if i < num_processes - 1 else size
|
||||
blocks.append(matrix[start_row:end_row, start_row:end_row])
|
||||
|
||||
pool = Pool(processes=num_processes)
|
||||
dets = pool.map(determinant_block, blocks)
|
||||
pool.close()
|
||||
pool.join()
|
||||
|
||||
return np.prod(dets)
|
||||
|
||||
|
||||
def benchmark(size, num_processes):
|
||||
matrix = np.random.rand(size, size)
|
||||
|
||||
start = time.time()
|
||||
det_parallel = determinant_parallel(matrix, num_processes)
|
||||
end = time.time()
|
||||
print(f"Матрица {size}x{size} с {num_processes} процессами заняла {end - start:.5f} сек (Параллельно)")
|
||||
|
||||
start = time.time()
|
||||
det_seq = determinant_block(matrix)
|
||||
end = time.time()
|
||||
print(f"Матрица {size}x{size} последовательный вычисление заняло {end - start:.5f} сек (Последовательно)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Вычисление детерминанта с параллельной обработкой")
|
||||
parser.add_argument("--processes", type=int, default=4)
|
||||
args = parser.parse_args()
|
||||
|
||||
sizes = [100, 300, 500]
|
||||
for size in sizes:
|
||||
benchmark(size, args.processes)
|
BIN
chernyshov_nikita_lab_6/img1.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
chernyshov_nikita_lab_6/img2.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
chernyshov_nikita_lab_6/img3.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
chernyshov_nikita_lab_6/img4.png
Normal file
After Width: | Height: | Size: 39 KiB |