Compare commits
22 Commits
8f24aad349
...
13b5dfc707
Author | SHA1 | Date | |
---|---|---|---|
13b5dfc707 | |||
5d3517c2b0 | |||
481631cda5 | |||
3b842c2228 | |||
c4b8f4b4de | |||
85567eea48 | |||
ea8da8c665 | |||
|
a6a247cabf | ||
|
f5194bf885 | ||
|
12cd98aa7d | ||
|
3db4a0fcd4 | ||
a4f9cf13cc | |||
75b118ba6e | |||
d8441a0989 | |||
1213b5db3c | |||
|
f0b48bba28 | ||
e1950c80ea | |||
5586bec4b8 | |||
4c74a16753 | |||
a830cb2198 | |||
9d0fa199f7 | |||
6de5160da9 |
2
bogdanov_dmitry_lab_2/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
data/
|
||||||
|
result/
|
41
bogdanov_dmitry_lab_2/README.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# Лабораторная работа №2
|
||||||
|
|
||||||
|
## Богданов Дмитрий ПИбд-42
|
||||||
|
|
||||||
|
### Для выполнения была проделана следующая работа:
|
||||||
|
Были написаны и развернуты 3 сервиса: генератор файлов, 2 приложения для работы с этими файлами по вариантам 2 и 1 соответственно:
|
||||||
|
|
||||||
|
Вариант 2 (для первого приложения):
|
||||||
|
|
||||||
|
```Формирует файл /var/result/data.txt из первых строк всех файлов каталога /var/data.```
|
||||||
|
|
||||||
|
Вариант 1 (для второго приложения):
|
||||||
|
|
||||||
|
```Ищет набольшее число из файла /var/data/data.txt и сохраняет его вторую степень в /var/result/result.txt.```
|
||||||
|
|
||||||
|
Приложения работают совместно, используя общий монтированный том для записи и получения информации:
|
||||||
|
```
|
||||||
|
volumes:
|
||||||
|
- ./data:/var/data
|
||||||
|
```
|
||||||
|
```
|
||||||
|
volumes:
|
||||||
|
- ./data:/var/data
|
||||||
|
- ./result:/var/result
|
||||||
|
```
|
||||||
|
```
|
||||||
|
volumes:
|
||||||
|
- ./result:/var/result
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Запуск лабораторной:
|
||||||
|
Необходимо перейти в папку с файлом docker-compose.yaml и ввести следующую команду:
|
||||||
|
```
|
||||||
|
docker compose up --build
|
||||||
|
```
|
||||||
|
Сервис генератора сгенерирует папки data и result, где будут сгенерированы входные файлы и файл-результат их обработки соответственно.
|
||||||
|
|
||||||
|
## Видео с результатом запуска:
|
||||||
|
|
||||||
|
Видео-демонстрацию работы можно посмотреть по данной [ссылке](https://drive.google.com/file/d/1CmVZjJuMStqNFFKbsMLjw4ihTiMnR7it/view).
|
7
bogdanov_dmitry_lab_2/app-1/Dockerfile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
FROM python:latest
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY app.py /app/
|
||||||
|
|
||||||
|
CMD ["python", "app.py"]
|
30
bogdanov_dmitry_lab_2/app-1/app.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
# Вариант 2 - Формирует файл /var/result/data.txt из первых строк всех файлов каталога /var/data.
|
||||||
|
def solve(dir_files, dir_result, filename_result):
|
||||||
|
# Получаем список файлов в директории
|
||||||
|
filenames = os.listdir(dir_files)
|
||||||
|
result = ''
|
||||||
|
# Проходим через каждый файл
|
||||||
|
for filename in filenames:
|
||||||
|
filepath = os.path.join(dir_files, filename)
|
||||||
|
file = open(filepath, "r")
|
||||||
|
# Читаем первую строку, добавляем к результату
|
||||||
|
result += f"{file.readline()}"
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
# Если директории для сохранения результата нет - создаём
|
||||||
|
if not os.path.exists(dir_result):
|
||||||
|
os.makedirs(dir_result)
|
||||||
|
# Если директория с результатом не пустая - завершаем работу
|
||||||
|
if os.listdir(dir_result):
|
||||||
|
return
|
||||||
|
# Пишем результат в файл
|
||||||
|
filepath_result = os.path.join(dir_result, filename_result)
|
||||||
|
result_file = open(filepath_result, "w")
|
||||||
|
result_file.write(result)
|
||||||
|
print(f"Результат записан в файл {filepath_result}")
|
||||||
|
result_file.close()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solve('/var/data', '/var/result', 'data.txt')
|
7
bogdanov_dmitry_lab_2/app-2/Dockerfile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
FROM python:latest
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY app.py /app/
|
||||||
|
|
||||||
|
CMD ["python", "app.py"]
|
21
bogdanov_dmitry_lab_2/app-2/app.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
# Вариант 1 - Ищет набольшее число из файла /var/data/data.txt и сохраняет его вторую степень в /var/result/result.txt.
|
||||||
|
def solve(dir_input, dir_result, filename_result):
|
||||||
|
file_input = open(os.path.join(dir_input, 'data.txt'))
|
||||||
|
# Считываем все числа из файла
|
||||||
|
inputs = [int(line) for line in file_input.readlines()]
|
||||||
|
if inputs:
|
||||||
|
# Максимальное число
|
||||||
|
max_num = max(inputs)
|
||||||
|
print(f"Наибольшее число: {max_num}")
|
||||||
|
# Возводим во 2 степень
|
||||||
|
result = max(inputs) ** 2
|
||||||
|
file_result = open(os.path.join(dir_result, filename_result), "w")
|
||||||
|
# Пишем результат в файл
|
||||||
|
file_result.write(str(result))
|
||||||
|
print(f"Получен результат {result}")
|
||||||
|
file_result.close()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solve("/var/result", '/var/result', 'result.txt')
|
7
bogdanov_dmitry_lab_2/app-generator/Dockerfile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
FROM python:latest
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY generator.py /app/
|
||||||
|
|
||||||
|
CMD ["python", "generate_files.py"]
|
30
bogdanov_dmitry_lab_2/app-generator/generator.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import os
|
||||||
|
import random as rnd
|
||||||
|
import string
|
||||||
|
|
||||||
|
# Генератор названий файлов
|
||||||
|
def generate_filename(l):
|
||||||
|
return ''.join(rnd.choices(string.ascii_lowercase + string.digits, k=l)) + '.txt'
|
||||||
|
|
||||||
|
def generate_files(dir, num_files, num_lines):
|
||||||
|
# Если директории для сохранения файлов нет - создаём
|
||||||
|
if not os.path.exists(dir):
|
||||||
|
os.makedirs(dir)
|
||||||
|
|
||||||
|
# Если директория для сохранения файлов не пустая - завершаем работу
|
||||||
|
if os.listdir(dir):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Создание файлов
|
||||||
|
for i in range(num_files):
|
||||||
|
filename = generate_filename(20)
|
||||||
|
filepath = os.path.join(dir, filename)
|
||||||
|
|
||||||
|
file = open(filepath, "w")
|
||||||
|
# Запись строк в файл
|
||||||
|
for j in range(num_lines):
|
||||||
|
file.write(f"{rnd.randint(-1000, 1000)}\n")
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
generate_files('/var/data', 50, 50)
|
27
bogdanov_dmitry_lab_2/docker-compose.yaml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
services:
|
||||||
|
# Генератор файлов
|
||||||
|
generator:
|
||||||
|
build:
|
||||||
|
context: ./app-generator # Путь к контексту (докер файл + скрипт)
|
||||||
|
volumes:
|
||||||
|
- ./data:/var/data # Папка контейнера : папка локальная
|
||||||
|
entrypoint: python generator.py # Точка входа
|
||||||
|
|
||||||
|
# Первое приложение
|
||||||
|
app1:
|
||||||
|
build:
|
||||||
|
context: ./app-1 # Путь к контексту
|
||||||
|
volumes:
|
||||||
|
- ./data:/var/data # Монтирование папок
|
||||||
|
- ./result:/var/result
|
||||||
|
depends_on:
|
||||||
|
- generator # Указываем, что запускается только после успешной работы сервиса generator
|
||||||
|
|
||||||
|
# Второе приложение, настройка аналогична сервисам выше
|
||||||
|
app2:
|
||||||
|
build:
|
||||||
|
context: ./app-2
|
||||||
|
volumes:
|
||||||
|
- ./result:/var/result
|
||||||
|
depends_on:
|
||||||
|
- app1
|
50
borschevskaya_anna_lab_4/README.md
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
# Отчет. Лабораторная работа 4
|
||||||
|
|
||||||
|
## Описание
|
||||||
|
В ходе лабораторной работы были изучены главы туториала о работе с RabbitMQ. Результат выполнения заданий каждой главы
|
||||||
|
отражен на скриншотах в папке /images:
|
||||||
|
- Tutorial-Task1.png
|
||||||
|
![Tutorial-Task1](images/Tutorial-Task1.png)
|
||||||
|
- Tutorial-Task2.png
|
||||||
|
![Tutorial-Task2](images/Tutorial-Task2.png)
|
||||||
|
- Tutorial-Task3.png
|
||||||
|
![Tutorial-Task3](images/Tutorial-Task3.png)
|
||||||
|
|
||||||
|
Задание из 3-ей главы туториала было расширено условиями, которые были поставлены в задании к данной лабораторной работе.
|
||||||
|
Для демонстрации работы сервисов посредством ассинхронного общения через брокер сообщений RabbitMQ была выбрана
|
||||||
|
предметная область "Обработка заказов".
|
||||||
|
|
||||||
|
Сервис-издатель "Publisher" публикует в очередь сообщений событие поступления заказа с некоторым номером.
|
||||||
|
|
||||||
|
Сервисы-подписчики обрабатывают сообщения о заказах, при этом подписчики обрабатывают сообщение по-разному. Один вид
|
||||||
|
подписчика обрабатывает с задержкой в несколько секунд, другой - "мгновенно", они получают одни и те жа сообщения,
|
||||||
|
но соединены с разными очередями.
|
||||||
|
В качестве эксперимента изначально были запущены по одному экземпляру каждого вида.
|
||||||
|
На изображении Consumer2.png представлена работа мгновенно обрабатывающего подписчика. Он справляется с нагрузкой,
|
||||||
|
так как размер очереди не растет.
|
||||||
|
![Consumer 2](images/Consumer2.png)
|
||||||
|
На изображении Consumer1.png представлена работа подписчика, обрабатывающего сообщения с задержкой. Как мы видим,
|
||||||
|
в очереди накапливаются сообщения в состоянии 'Ready' - эти сообщения готовы для того, чтобы быть доставленными подписчикам.
|
||||||
|
Сервис не справляется с нагрузкой, так как отправляются сообщения быстрее, чем обрабатываются.
|
||||||
|
![Consumer 1](images/Consumer1.png)
|
||||||
|
Для того, чтобы обеспечить равную скорость отправки и обработки, увеличиваем количество экземпляров-подписчиков данного типа до трех.
|
||||||
|
На изображении видно, что теперь длина очереди не растет и система справляется с поступающими сообщениями. Также скорость "publish" и
|
||||||
|
"consumer ack" стали равны.
|
||||||
|
![Consumer 1](images/Consumer1-scaling.png)
|
||||||
|
## Как запустить
|
||||||
|
Для того, чтобы запустить сервисы, необходимо выполнить следующие действия:
|
||||||
|
1. Установить и запустить Docker Engine или Docker Desktop
|
||||||
|
2. Через консоль перейти в папку, в которой расположен файл docker-compose.yml
|
||||||
|
3. Выполнить команду для запуска брокера сообщений rabbitmq:
|
||||||
|
```
|
||||||
|
docker compose up rabbit -d
|
||||||
|
```
|
||||||
|
4. Выполнить команду для запуска остальных контейнеров:
|
||||||
|
```
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
Такой порядок запуска важен для того, чтобы брокер сообщений успел полностью запуститься
|
||||||
|
и произвести действия для того, чтобы быть готовым принимать соединения от сервисов. Потому что указания depends_on не хватает
|
||||||
|
для отслеживания завершения всех необходимых подготовительных процессов брокера.
|
||||||
|
## Видео-отчет
|
||||||
|
Работоспособность лабораторной работы можно оценить в следующем [видео](https://disk.yandex.ru/i/G0vsfp7vwazYHw).
|
23
borschevskaya_anna_lab_4/consumer-app/Dockerfile
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Используем образ Maven для сборки
|
||||||
|
FROM maven:3.8-eclipse-temurin-21-alpine AS build
|
||||||
|
|
||||||
|
# Устанавливаем рабочую директорию
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Копируем остальные исходные файлы
|
||||||
|
COPY pom.xml .
|
||||||
|
COPY src src
|
||||||
|
|
||||||
|
# Собираем весь проект
|
||||||
|
RUN mvn clean package -DskipTests
|
||||||
|
RUN mvn dependency:copy-dependencies
|
||||||
|
|
||||||
|
# Используем официальный образ JDK для запуска собранного jar-файла
|
||||||
|
FROM eclipse-temurin:21-jdk-alpine
|
||||||
|
|
||||||
|
# Копируем jar-файл из предыдущего этапа
|
||||||
|
COPY --from=build /app/target/*.jar /app.jar
|
||||||
|
COPY --from=build /app/target/dependency /
|
||||||
|
|
||||||
|
# Указываем команду для запуска приложения
|
||||||
|
CMD ["java", "-jar", "app.jar"]
|
50
borschevskaya_anna_lab_4/consumer-app/pom.xml
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>ru.somecompany</groupId>
|
||||||
|
<artifactId>consumer-app</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>3.2.3</version>
|
||||||
|
<relativePath/>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
|
<maven.compiler.target>21</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.rabbitmq</groupId>
|
||||||
|
<artifactId>amqp-client</artifactId>
|
||||||
|
<version>5.22.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.18.30</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,15 @@
|
|||||||
|
package ru.somecompany;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
|
||||||
|
import ru.somecompany.config.property.RabbitProperties;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
@ConfigurationPropertiesScan(basePackageClasses = RabbitProperties.class)
|
||||||
|
public class Main {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(Main.class, args);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package ru.somecompany.config;
|
||||||
|
|
||||||
|
import com.rabbitmq.client.BuiltinExchangeType;
|
||||||
|
import com.rabbitmq.client.Channel;
|
||||||
|
import com.rabbitmq.client.Connection;
|
||||||
|
import com.rabbitmq.client.ConnectionFactory;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import ru.somecompany.config.property.RabbitProperties;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ConnectionFactoryConfig {
|
||||||
|
|
||||||
|
private final RabbitProperties rabbitProperties;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ConnectionFactory connectionFactory() {
|
||||||
|
ConnectionFactory factory = new ConnectionFactory();
|
||||||
|
factory.setHost(rabbitProperties.getHost());
|
||||||
|
factory.setPort(rabbitProperties.getPort());
|
||||||
|
return factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Connection connection(ConnectionFactory connectionFactory) throws IOException, TimeoutException {
|
||||||
|
return connectionFactory.newConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Channel channel(Connection connection) throws IOException {
|
||||||
|
var exchange = rabbitProperties.getExchange();
|
||||||
|
var queue = rabbitProperties.getQueue();
|
||||||
|
var channel = connection.createChannel();
|
||||||
|
|
||||||
|
channel.exchangeDeclare(exchange, BuiltinExchangeType.FANOUT);
|
||||||
|
channel.queueDeclare(queue, true, false, true, null);
|
||||||
|
channel.queueBind(queue, exchange, "");
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package ru.somecompany.config.property;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ConfigurationProperties(prefix = "app.rabbit-properties")
|
||||||
|
public class RabbitProperties {
|
||||||
|
|
||||||
|
private String host;
|
||||||
|
|
||||||
|
private Integer port;
|
||||||
|
|
||||||
|
private Integer delay;
|
||||||
|
|
||||||
|
private String queue;
|
||||||
|
|
||||||
|
private String exchange;
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
package ru.somecompany.consumer;
|
||||||
|
|
||||||
|
import com.rabbitmq.client.AMQP;
|
||||||
|
import com.rabbitmq.client.Channel;
|
||||||
|
import com.rabbitmq.client.Connection;
|
||||||
|
import com.rabbitmq.client.DefaultConsumer;
|
||||||
|
import com.rabbitmq.client.Envelope;
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import jakarta.annotation.PreDestroy;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import ru.somecompany.config.property.RabbitProperties;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class Consumer {
|
||||||
|
|
||||||
|
private final RabbitProperties rabbitProperties;
|
||||||
|
|
||||||
|
private final Connection connection;
|
||||||
|
private final Channel channel;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void consume() {
|
||||||
|
try {
|
||||||
|
channel.basicQos(1);
|
||||||
|
channel.basicConsume(rabbitProperties.getQueue(), false, new DefaultConsumer(channel) {
|
||||||
|
@Override
|
||||||
|
public void handleDelivery(String consumerTag,
|
||||||
|
Envelope envelope,
|
||||||
|
AMQP.BasicProperties properties,
|
||||||
|
byte[] body) throws IOException {
|
||||||
|
long deliveryTag = envelope.getDeliveryTag();
|
||||||
|
|
||||||
|
String message = new String(body, StandardCharsets.UTF_8);
|
||||||
|
System.out.println(" [x] Received '" + message + "'");
|
||||||
|
|
||||||
|
var delay = rabbitProperties.getDelay();
|
||||||
|
try {
|
||||||
|
doWork(delay);
|
||||||
|
} finally {
|
||||||
|
System.out.println(" [x] Processed '" + message + "'");
|
||||||
|
channel.basicAck(deliveryTag, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception exception) {
|
||||||
|
log.error("Error while set up connection with rabbit", exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void doWork(Integer delay) {
|
||||||
|
if (delay > 0) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(delay);
|
||||||
|
} catch (InterruptedException _ignored) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void cleanUp() throws Exception {
|
||||||
|
if (channel != null) {
|
||||||
|
channel.close();
|
||||||
|
}
|
||||||
|
if (connection != null) {
|
||||||
|
connection.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
server:
|
||||||
|
port: ${SERVER_PORT:8081}
|
||||||
|
|
||||||
|
app:
|
||||||
|
rabbit-properties:
|
||||||
|
host: ${RABBIT_HOST:localhost}
|
||||||
|
port: ${RABBIT_PORT:5672}
|
||||||
|
delay: ${PROCESS_DELAY:0}
|
||||||
|
queue: ${QUEUE_NAME:queue-1}
|
||||||
|
exchange: ${EXCHANGE_NAME:order-events}
|
79
borschevskaya_anna_lab_4/docker-compose.yml
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
services:
|
||||||
|
rabbit:
|
||||||
|
container_name: rabbit
|
||||||
|
image: rabbitmq:3-management
|
||||||
|
ports:
|
||||||
|
- "15672:15672"
|
||||||
|
- "5672:5672"
|
||||||
|
- "5671:5671"
|
||||||
|
networks:
|
||||||
|
- local
|
||||||
|
publisher:
|
||||||
|
build: ./publisher-app
|
||||||
|
container_name: publisher
|
||||||
|
depends_on:
|
||||||
|
- rabbit
|
||||||
|
environment:
|
||||||
|
RABBIT_HOST: rabbit
|
||||||
|
RABBIT_PORT: 5672
|
||||||
|
networks:
|
||||||
|
- local
|
||||||
|
consumer-1:
|
||||||
|
build: ./consumer-app
|
||||||
|
container_name: consumer-1
|
||||||
|
depends_on:
|
||||||
|
- rabbit
|
||||||
|
- publisher
|
||||||
|
environment:
|
||||||
|
RABBIT_HOST: rabbit
|
||||||
|
RABBIT_PORT: 5672
|
||||||
|
PROCESS_DELAY: 3000
|
||||||
|
QUEUE_NAME: queue1
|
||||||
|
EXCHANGE_NAME: order-events
|
||||||
|
networks:
|
||||||
|
- local
|
||||||
|
consumer-2:
|
||||||
|
build: ./consumer-app
|
||||||
|
container_name: consumer-2
|
||||||
|
depends_on:
|
||||||
|
- rabbit
|
||||||
|
- publisher
|
||||||
|
environment:
|
||||||
|
RABBIT_HOST: rabbit
|
||||||
|
RABBIT_PORT: 5672
|
||||||
|
PROCESS_DELAY: 0
|
||||||
|
QUEUE_NAME: queue2
|
||||||
|
EXCHANGE_NAME: order-events
|
||||||
|
networks:
|
||||||
|
- local
|
||||||
|
consumer-12:
|
||||||
|
build: ./consumer-app
|
||||||
|
container_name: consumer-12
|
||||||
|
depends_on:
|
||||||
|
- rabbit
|
||||||
|
- publisher
|
||||||
|
environment:
|
||||||
|
RABBIT_HOST: rabbit
|
||||||
|
RABBIT_PORT: 5672
|
||||||
|
PROCESS_DELAY: 3000
|
||||||
|
QUEUE_NAME: queue1
|
||||||
|
EXCHANGE_NAME: order-events
|
||||||
|
networks:
|
||||||
|
- local
|
||||||
|
consumer-13:
|
||||||
|
build: ./consumer-app
|
||||||
|
container_name: consumer-13
|
||||||
|
depends_on:
|
||||||
|
- rabbit
|
||||||
|
- publisher
|
||||||
|
environment:
|
||||||
|
RABBIT_HOST: rabbit
|
||||||
|
RABBIT_PORT: 5672
|
||||||
|
PROCESS_DELAY: 3000
|
||||||
|
QUEUE_NAME: queue1
|
||||||
|
EXCHANGE_NAME: order-events
|
||||||
|
networks:
|
||||||
|
- local
|
||||||
|
|
||||||
|
networks:
|
||||||
|
local:
|
34
borschevskaya_anna_lab_4/helloworld-tutorial/pom.xml
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>ru.somecompany</groupId>
|
||||||
|
<artifactId>helloworld-tutorial</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
|
<maven.compiler.target>21</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.rabbitmq</groupId>
|
||||||
|
<artifactId>amqp-client</artifactId>
|
||||||
|
<version>5.22.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<version>1.7.5</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-log4j12</artifactId>
|
||||||
|
<version>1.7.5</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@ -0,0 +1,28 @@
|
|||||||
|
package ru.somecompany;
|
||||||
|
|
||||||
|
import com.rabbitmq.client.Channel;
|
||||||
|
import com.rabbitmq.client.Connection;
|
||||||
|
import com.rabbitmq.client.ConnectionFactory;
|
||||||
|
import com.rabbitmq.client.DeliverCallback;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
|
||||||
|
private static final String QUEUE_NAME = "hello-world";
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
ConnectionFactory factory = new ConnectionFactory();
|
||||||
|
factory.setHost("localhost");
|
||||||
|
try(Connection connection = factory.newConnection();
|
||||||
|
Channel channel = connection.createChannel();) {
|
||||||
|
var sender = new Sender(channel);
|
||||||
|
var receiver = new Receiver(channel);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println(" [*] Error in Hello-World");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package ru.somecompany;
|
||||||
|
|
||||||
|
import com.rabbitmq.client.Channel;
|
||||||
|
import com.rabbitmq.client.DeliverCallback;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class Receiver {
|
||||||
|
|
||||||
|
private static final String QUEUE_NAME = "hello-world";
|
||||||
|
|
||||||
|
public Receiver(Channel channel) throws IOException {
|
||||||
|
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
|
||||||
|
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
|
||||||
|
String message = new String(delivery.getBody(), "UTF-8");
|
||||||
|
System.out.println(" [x] Received '" + message + "'");
|
||||||
|
};
|
||||||
|
channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> { });
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package ru.somecompany;
|
||||||
|
|
||||||
|
import com.rabbitmq.client.Channel;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class Sender {
|
||||||
|
|
||||||
|
private static final String QUEUE_NAME = "hello-world";
|
||||||
|
|
||||||
|
public Sender(Channel channel) throws IOException {
|
||||||
|
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
|
||||||
|
String message = "Hello World!";
|
||||||
|
channel.basicPublish("", QUEUE_NAME, null, message.getBytes(StandardCharsets.UTF_8));
|
||||||
|
System.out.println(" [x] Sent '" + message + "'");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
# Root logger option
|
||||||
|
log4j.rootLogger=INFO, stdout
|
||||||
|
|
||||||
|
# Direct log messages to stdout
|
||||||
|
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||||
|
log4j.appender.stdout.Target=System.out
|
||||||
|
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||||
|
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
|
BIN
borschevskaya_anna_lab_4/images/Consumer1-scaling.PNG
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
borschevskaya_anna_lab_4/images/Consumer1.PNG
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
borschevskaya_anna_lab_4/images/Consumer2.PNG
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
borschevskaya_anna_lab_4/images/Tutorial-Task1.PNG
Normal file
After Width: | Height: | Size: 101 KiB |
BIN
borschevskaya_anna_lab_4/images/Tutorial-Task2.PNG
Normal file
After Width: | Height: | Size: 128 KiB |
BIN
borschevskaya_anna_lab_4/images/Tutorial-Task3.PNG
Normal file
After Width: | Height: | Size: 848 KiB |
38
borschevskaya_anna_lab_4/publisher-app/.gitignore
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea/modules.xml
|
||||||
|
.idea/jarRepositories.xml
|
||||||
|
.idea/compiler.xml
|
||||||
|
.idea/libraries/
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### Eclipse ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
### Mac OS ###
|
||||||
|
.DS_Store
|
21
borschevskaya_anna_lab_4/publisher-app/Dockerfile
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Используем образ Maven для сборки
|
||||||
|
FROM maven:3.8-eclipse-temurin-21-alpine AS build
|
||||||
|
|
||||||
|
# Устанавливаем рабочую директорию
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Копируем остальные исходные файлы
|
||||||
|
COPY pom.xml .
|
||||||
|
COPY src src
|
||||||
|
|
||||||
|
# Собираем весь проект
|
||||||
|
RUN mvn clean package -DskipTests
|
||||||
|
|
||||||
|
# Используем официальный образ JDK для запуска собранного jar-файла
|
||||||
|
FROM eclipse-temurin:21-jdk-alpine
|
||||||
|
|
||||||
|
# Копируем jar-файл из предыдущего этапа
|
||||||
|
COPY --from=build /app/target/*.jar /app.jar
|
||||||
|
|
||||||
|
# Указываем команду для запуска приложения
|
||||||
|
CMD ["java", "-jar", "app.jar"]
|
49
borschevskaya_anna_lab_4/publisher-app/pom.xml
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>ru.somecompany</groupId>
|
||||||
|
<artifactId>publisher-app</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>3.2.3</version>
|
||||||
|
<relativePath/>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
|
<maven.compiler.target>21</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.18.30</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.rabbitmq</groupId>
|
||||||
|
<artifactId>amqp-client</artifactId>
|
||||||
|
<version>5.22.0</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
@ -0,0 +1,17 @@
|
|||||||
|
package ru.somecompany;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import ru.somecompany.config.property.RabbitProperties;
|
||||||
|
|
||||||
|
@EnableScheduling
|
||||||
|
@SpringBootApplication
|
||||||
|
@ConfigurationPropertiesScan(basePackageClasses = RabbitProperties.class)
|
||||||
|
public class Main {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(Main.class, args);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package ru.somecompany.config;
|
||||||
|
|
||||||
|
import com.rabbitmq.client.BuiltinExchangeType;
|
||||||
|
import com.rabbitmq.client.Channel;
|
||||||
|
import com.rabbitmq.client.Connection;
|
||||||
|
import com.rabbitmq.client.ConnectionFactory;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import ru.somecompany.config.property.RabbitProperties;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ConnectionFactoryConfig {
|
||||||
|
|
||||||
|
private final RabbitProperties rabbitProperties;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ConnectionFactory connectionFactory() {
|
||||||
|
ConnectionFactory factory = new ConnectionFactory();
|
||||||
|
factory.setHost(rabbitProperties.getHost());
|
||||||
|
factory.setPort(rabbitProperties.getPort());
|
||||||
|
return factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Connection connection(ConnectionFactory connectionFactory) throws IOException, TimeoutException {
|
||||||
|
return connectionFactory.newConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Channel channel(Connection connection) throws IOException {
|
||||||
|
var channel = connection.createChannel();
|
||||||
|
channel.exchangeDeclare(rabbitProperties.getExchange(), BuiltinExchangeType.FANOUT);
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package ru.somecompany.config.property;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ConfigurationProperties(prefix = "app.rabbit-properties")
|
||||||
|
public class RabbitProperties {
|
||||||
|
|
||||||
|
private String host;
|
||||||
|
|
||||||
|
private Integer port;
|
||||||
|
|
||||||
|
private String exchange;
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package ru.somecompany.scheduler;
|
||||||
|
|
||||||
|
import com.rabbitmq.client.BuiltinExchangeType;
|
||||||
|
import com.rabbitmq.client.Channel;
|
||||||
|
import com.rabbitmq.client.Connection;
|
||||||
|
import com.rabbitmq.client.ConnectionFactory;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SenderScheduler {
|
||||||
|
|
||||||
|
private static final String EXCHANGE_NAME = "order-events";
|
||||||
|
private static final String MESSAGE = "Поступил заказ №%d";
|
||||||
|
private Integer index = 0;
|
||||||
|
|
||||||
|
private final ConnectionFactory connectionFactory;
|
||||||
|
private final Connection connection;
|
||||||
|
private final Channel channel;
|
||||||
|
|
||||||
|
@Scheduled(cron = "*/1 * * * * *")
|
||||||
|
public void sendMessage() {
|
||||||
|
try {
|
||||||
|
var message = String.format(MESSAGE, index);
|
||||||
|
|
||||||
|
channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes(StandardCharsets.UTF_8));
|
||||||
|
index++;
|
||||||
|
System.out.println(" [x] Sent '" + message + "'");
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println(" [x] Error while send message");
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
server:
|
||||||
|
port: ${SERVER_PORT:8080}
|
||||||
|
|
||||||
|
app:
|
||||||
|
rabbit-properties:
|
||||||
|
host: ${RABBIT_HOST:localhost}
|
||||||
|
port: ${RABBIT_PORT:5672}
|
||||||
|
exchange: ${EXCHANGE_NAME:order-events}
|
30
borschevskaya_anna_lab_4/workqueue-tutorial/pom.xml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>ru.somecompany</groupId>
|
||||||
|
<artifactId>workqueue-tutorial</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
|
<maven.compiler.target>21</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.rabbitmq</groupId>
|
||||||
|
<artifactId>amqp-client</artifactId>
|
||||||
|
<version>5.22.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-log4j12</artifactId>
|
||||||
|
<version>1.7.5</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,23 @@
|
|||||||
|
package ru.somecompany;
|
||||||
|
|
||||||
|
import com.rabbitmq.client.Channel;
|
||||||
|
import com.rabbitmq.client.Connection;
|
||||||
|
import com.rabbitmq.client.ConnectionFactory;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
|
||||||
|
public static final String QUEUE_NAME = "task_queue";
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
ConnectionFactory factory = new ConnectionFactory();
|
||||||
|
factory.setHost("localhost");
|
||||||
|
try(Connection connection = factory.newConnection();
|
||||||
|
Channel channel = connection.createChannel();) {
|
||||||
|
var sender = new Sender(channel);
|
||||||
|
sender.send("Work Queue message");
|
||||||
|
var receiver = new Receiver(channel);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println(" [*] Error in Work-Queue: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package ru.somecompany;
|
||||||
|
|
||||||
|
import com.rabbitmq.client.Channel;
|
||||||
|
import com.rabbitmq.client.DeliverCallback;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import static ru.somecompany.Main.QUEUE_NAME;
|
||||||
|
|
||||||
|
public class Receiver {
|
||||||
|
|
||||||
|
public Receiver(Channel channel) throws IOException {
|
||||||
|
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
|
||||||
|
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
|
||||||
|
|
||||||
|
channel.basicQos(1);
|
||||||
|
|
||||||
|
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
|
||||||
|
String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
System.out.println(" [x] Received '" + message + "'");
|
||||||
|
try {
|
||||||
|
doWork(message);
|
||||||
|
} finally {
|
||||||
|
System.out.println(" [x] Done");
|
||||||
|
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> { });
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void doWork(String task) {
|
||||||
|
for (char ch : task.toCharArray()) {
|
||||||
|
if (ch == '.') {
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException _ignored) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package ru.somecompany;
|
||||||
|
|
||||||
|
import com.rabbitmq.client.Channel;
|
||||||
|
import com.rabbitmq.client.MessageProperties;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import static ru.somecompany.Main.QUEUE_NAME;
|
||||||
|
|
||||||
|
public class Sender {
|
||||||
|
|
||||||
|
private Channel channel;
|
||||||
|
|
||||||
|
public Sender(Channel channel) throws IOException {
|
||||||
|
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
|
||||||
|
this.channel = channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(String msg) throws IOException {
|
||||||
|
String message = String.join(" ", msg);
|
||||||
|
|
||||||
|
channel.basicPublish("", QUEUE_NAME,
|
||||||
|
MessageProperties.PERSISTENT_TEXT_PLAIN,
|
||||||
|
message.getBytes("UTF-8"));
|
||||||
|
System.out.println(" [x] Sent '" + message + "'");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
# Root logger option
|
||||||
|
log4j.rootLogger=INFO, stdout
|
||||||
|
|
||||||
|
# Direct log messages to stdout
|
||||||
|
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||||
|
log4j.appender.stdout.Target=System.out
|
||||||
|
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||||
|
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
|
30
dozorova_alena_lab_4/ConsumerDelay/.dockerignore
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
**/.classpath
|
||||||
|
**/.dockerignore
|
||||||
|
**/.env
|
||||||
|
**/.git
|
||||||
|
**/.gitignore
|
||||||
|
**/.project
|
||||||
|
**/.settings
|
||||||
|
**/.toolstarget
|
||||||
|
**/.vs
|
||||||
|
**/.vscode
|
||||||
|
**/*.*proj.user
|
||||||
|
**/*.dbmdl
|
||||||
|
**/*.jfm
|
||||||
|
**/azds.yaml
|
||||||
|
**/bin
|
||||||
|
**/charts
|
||||||
|
**/docker-compose*
|
||||||
|
**/Dockerfile*
|
||||||
|
**/node_modules
|
||||||
|
**/npm-debug.log
|
||||||
|
**/obj
|
||||||
|
**/secrets.dev.yaml
|
||||||
|
**/values.dev.yaml
|
||||||
|
LICENSE
|
||||||
|
README.md
|
||||||
|
!**/.gitignore
|
||||||
|
!.git/HEAD
|
||||||
|
!.git/config
|
||||||
|
!.git/packed-refs
|
||||||
|
!.git/refs/heads/**
|
17
dozorova_alena_lab_4/ConsumerDelay/ConsumerDelay.csproj
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
|
<DockerfileContext>.</DockerfileContext>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1" />
|
||||||
|
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ActiveDebugProfile>Container (Dockerfile)</ActiveDebugProfile>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
25
dozorova_alena_lab_4/ConsumerDelay/ConsumerDelay.sln
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.10.35004.147
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsumerDelay", "ConsumerDelay.csproj", "{4DD86D5F-D90D-4BBB-AAA4-F16DA855B51E}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{4DD86D5F-D90D-4BBB-AAA4-F16DA855B51E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{4DD86D5F-D90D-4BBB-AAA4-F16DA855B51E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{4DD86D5F-D90D-4BBB-AAA4-F16DA855B51E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{4DD86D5F-D90D-4BBB-AAA4-F16DA855B51E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {3E7AED20-0868-42FE-9C39-581BC9D2BB22}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
22
dozorova_alena_lab_4/ConsumerDelay/Dockerfile
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||||
|
ARG BUILD_CONFIGURATION=Release
|
||||||
|
WORKDIR /src
|
||||||
|
COPY ["ConsumerDelay.csproj", "."]
|
||||||
|
RUN dotnet restore "./ConsumerDelay.csproj"
|
||||||
|
COPY . .
|
||||||
|
WORKDIR "/src/."
|
||||||
|
RUN dotnet build "./ConsumerDelay.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
||||||
|
|
||||||
|
FROM build AS publish
|
||||||
|
ARG BUILD_CONFIGURATION=Release
|
||||||
|
RUN dotnet publish "./ConsumerDelay.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
||||||
|
|
||||||
|
FROM base AS final
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=publish /app/publish .
|
||||||
|
ENTRYPOINT ["dotnet", "ConsumerDelay.dll"]
|
24
dozorova_alena_lab_4/ConsumerDelay/Program.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using ConsumerDelay;
|
||||||
|
|
||||||
|
var rabbitHost = Environment.GetEnvironmentVariable("RABBIT_HOST") ?? "localhost";
|
||||||
|
var rabbitUsername = Environment.GetEnvironmentVariable("RABBIT_USERNAME") ?? "user";
|
||||||
|
var rabbitPassword = Environment.GetEnvironmentVariable("RABBIT_PASSWORD") ?? "password";
|
||||||
|
var rabbitExchange = Environment.GetEnvironmentVariable("RABBIT_EXCHANGE") ?? "ReportIn";
|
||||||
|
var rabbitQueue = Environment.GetEnvironmentVariable("RABBIT_QUEUE") ?? "Second";
|
||||||
|
|
||||||
|
Thread.Sleep(2000);
|
||||||
|
|
||||||
|
var receiver = new Receiver(rabbitHost, rabbitUsername, rabbitPassword);
|
||||||
|
|
||||||
|
receiver.SubscribeTo(rabbitExchange, (message) =>
|
||||||
|
{
|
||||||
|
var rnd = new Random();
|
||||||
|
|
||||||
|
Console.WriteLine($"Пришло сообщение: {message}");
|
||||||
|
|
||||||
|
Thread.Sleep(rnd.Next(2000, 3000));
|
||||||
|
Console.WriteLine($"Обработка сообщения завершена");
|
||||||
|
},
|
||||||
|
rabbitQueue);
|
||||||
|
|
||||||
|
while (true) ;
|
82
dozorova_alena_lab_4/ConsumerDelay/Receiver.cs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
using RabbitMQ.Client;
|
||||||
|
using RabbitMQ.Client.Events;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ConsumerDelay
|
||||||
|
{
|
||||||
|
public class Receiver : IDisposable
|
||||||
|
{
|
||||||
|
private readonly ConnectionFactory _connectionFactory;
|
||||||
|
private readonly IConnection _connection;
|
||||||
|
private readonly IModel _channel;
|
||||||
|
|
||||||
|
public Dictionary<string, HashSet<string>> Queues { get; private set; } = new();
|
||||||
|
|
||||||
|
public Receiver(string brockerHost, string brockerUsername, string brockerPassword)
|
||||||
|
{
|
||||||
|
_connectionFactory = new ConnectionFactory() { HostName = brockerHost, UserName = brockerUsername, Password = brockerPassword };
|
||||||
|
_connection = _connectionFactory.CreateConnection();
|
||||||
|
_channel = _connection.CreateModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SubscribeTo(string exchange, Action<string> handler, string? queueName = null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!Queues.ContainsKey(exchange))
|
||||||
|
{
|
||||||
|
_channel.ExchangeDeclare(exchange: "logs", type: ExchangeType.Fanout);
|
||||||
|
Queues.Add(exchange, new HashSet<string>());
|
||||||
|
}
|
||||||
|
if (queueName != null)
|
||||||
|
_channel.QueueDeclare(queue: queueName,
|
||||||
|
durable: true,
|
||||||
|
exclusive: false,
|
||||||
|
autoDelete: false,
|
||||||
|
arguments: null);
|
||||||
|
|
||||||
|
queueName = queueName ?? _channel.QueueDeclare().QueueName;
|
||||||
|
|
||||||
|
|
||||||
|
_channel.QueueBind(queue: queueName,
|
||||||
|
exchange: exchange,
|
||||||
|
routingKey: string.Empty);
|
||||||
|
|
||||||
|
var consumer = new EventingBasicConsumer(_channel);
|
||||||
|
consumer.Received += (model, ea) =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var message = Encoding.UTF8.GetString(ea.Body.ToArray());
|
||||||
|
handler(message);
|
||||||
|
_channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
_channel.BasicConsume(queue: queueName,
|
||||||
|
autoAck: false,
|
||||||
|
consumer: consumer);
|
||||||
|
|
||||||
|
Queues[exchange].Add(queueName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex.Message);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
~Receiver() => Dispose();
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_connection.Dispose();
|
||||||
|
_channel.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
dozorova_alena_lab_4/ConsumerSimple/.dockerignore
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
**/.classpath
|
||||||
|
**/.dockerignore
|
||||||
|
**/.env
|
||||||
|
**/.git
|
||||||
|
**/.gitignore
|
||||||
|
**/.project
|
||||||
|
**/.settings
|
||||||
|
**/.toolstarget
|
||||||
|
**/.vs
|
||||||
|
**/.vscode
|
||||||
|
**/*.*proj.user
|
||||||
|
**/*.dbmdl
|
||||||
|
**/*.jfm
|
||||||
|
**/azds.yaml
|
||||||
|
**/bin
|
||||||
|
**/charts
|
||||||
|
**/docker-compose*
|
||||||
|
**/Dockerfile*
|
||||||
|
**/node_modules
|
||||||
|
**/npm-debug.log
|
||||||
|
**/obj
|
||||||
|
**/secrets.dev.yaml
|
||||||
|
**/values.dev.yaml
|
||||||
|
LICENSE
|
||||||
|
README.md
|
||||||
|
!**/.gitignore
|
||||||
|
!.git/HEAD
|
||||||
|
!.git/config
|
||||||
|
!.git/packed-refs
|
||||||
|
!.git/refs/heads/**
|
17
dozorova_alena_lab_4/ConsumerSimple/ConsumerSimple.csproj
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
|
<DockerfileContext>.</DockerfileContext>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1" />
|
||||||
|
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ActiveDebugProfile>Container (Dockerfile)</ActiveDebugProfile>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
25
dozorova_alena_lab_4/ConsumerSimple/ConsumerSimple.sln
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.10.35004.147
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsumerSimple", "ConsumerSimple.csproj", "{ACA8DE52-E29E-41BA-B3DA-213AF316685E}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{ACA8DE52-E29E-41BA-B3DA-213AF316685E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{ACA8DE52-E29E-41BA-B3DA-213AF316685E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{ACA8DE52-E29E-41BA-B3DA-213AF316685E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{ACA8DE52-E29E-41BA-B3DA-213AF316685E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {73265D6C-436C-470E-AE8A-17047E6C2ECC}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
22
dozorova_alena_lab_4/ConsumerSimple/Dockerfile
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||||
|
ARG BUILD_CONFIGURATION=Release
|
||||||
|
WORKDIR /src
|
||||||
|
COPY ["ConsumerSimple.csproj", "."]
|
||||||
|
RUN dotnet restore "./ConsumerSimple.csproj"
|
||||||
|
COPY . .
|
||||||
|
WORKDIR "/src/."
|
||||||
|
RUN dotnet build "./ConsumerSimple.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
||||||
|
|
||||||
|
FROM build AS publish
|
||||||
|
ARG BUILD_CONFIGURATION=Release
|
||||||
|
RUN dotnet publish "./ConsumerSimple.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
||||||
|
|
||||||
|
FROM base AS final
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=publish /app/publish .
|
||||||
|
ENTRYPOINT ["dotnet", "ConsumerSimple.dll"]
|
23
dozorova_alena_lab_4/ConsumerSimple/Program.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using ConsumerSimple;
|
||||||
|
|
||||||
|
var rabbitHost = Environment.GetEnvironmentVariable("RABBIT_HOST") ?? "localhost";
|
||||||
|
var rabbitUsername = Environment.GetEnvironmentVariable("RABBIT_USERNAME") ?? "user";
|
||||||
|
var rabbitPassword = Environment.GetEnvironmentVariable("RABBIT_PASSWORD") ?? "password";
|
||||||
|
var rabbitExchange = Environment.GetEnvironmentVariable("RABBIT_EXCHANGE") ?? "ReportIn";
|
||||||
|
var rabbitQueue = Environment.GetEnvironmentVariable("RABBIT_QUEUE") ?? "First";
|
||||||
|
|
||||||
|
Thread.Sleep(2000);
|
||||||
|
|
||||||
|
var receiver = new Receiver(rabbitHost, rabbitUsername, rabbitPassword);
|
||||||
|
|
||||||
|
receiver.SubscribeTo(rabbitExchange, (message) =>
|
||||||
|
{
|
||||||
|
var rnd = new Random();
|
||||||
|
|
||||||
|
Console.WriteLine($"Пришло сообщение: {message}");
|
||||||
|
|
||||||
|
Console.WriteLine($"Сообщение обрабатывается мгновенно");
|
||||||
|
},
|
||||||
|
rabbitQueue);
|
||||||
|
|
||||||
|
while (true) ;
|
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"ConsumerSimple": {
|
||||||
|
"commandName": "Project"
|
||||||
|
},
|
||||||
|
"Container (Dockerfile)": {
|
||||||
|
"commandName": "Docker"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
82
dozorova_alena_lab_4/ConsumerSimple/Receiver.cs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
using RabbitMQ.Client;
|
||||||
|
using RabbitMQ.Client.Events;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ConsumerSimple
|
||||||
|
{
|
||||||
|
public class Receiver : IDisposable
|
||||||
|
{
|
||||||
|
private readonly ConnectionFactory _connectionFactory;
|
||||||
|
private readonly IConnection _connection;
|
||||||
|
private readonly IModel _channel;
|
||||||
|
|
||||||
|
public Dictionary<string, HashSet<string>> Queues { get; private set; } = new();
|
||||||
|
|
||||||
|
public Receiver(string brockerHost, string brockerUsername, string brockerPassword)
|
||||||
|
{
|
||||||
|
_connectionFactory = new ConnectionFactory() { HostName = brockerHost, UserName = brockerUsername, Password = brockerPassword };
|
||||||
|
_connection = _connectionFactory.CreateConnection();
|
||||||
|
_channel = _connection.CreateModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SubscribeTo(string exchange, Action<string> handler, string? queueName = null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!Queues.ContainsKey(exchange))
|
||||||
|
{
|
||||||
|
_channel.ExchangeDeclare(exchange: "logs", type: ExchangeType.Fanout);
|
||||||
|
Queues.Add(exchange, new HashSet<string>());
|
||||||
|
}
|
||||||
|
if (queueName != null)
|
||||||
|
_channel.QueueDeclare(queue: queueName,
|
||||||
|
durable: true,
|
||||||
|
exclusive: false,
|
||||||
|
autoDelete: false,
|
||||||
|
arguments: null);
|
||||||
|
|
||||||
|
queueName = queueName ?? _channel.QueueDeclare().QueueName;
|
||||||
|
|
||||||
|
|
||||||
|
_channel.QueueBind(queue: queueName,
|
||||||
|
exchange: exchange,
|
||||||
|
routingKey: string.Empty);
|
||||||
|
|
||||||
|
var consumer = new EventingBasicConsumer(_channel);
|
||||||
|
consumer.Received += (model, ea) =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var message = Encoding.UTF8.GetString(ea.Body.ToArray());
|
||||||
|
handler(message);
|
||||||
|
_channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
_channel.BasicConsume(queue: queueName,
|
||||||
|
autoAck: false,
|
||||||
|
consumer: consumer);
|
||||||
|
|
||||||
|
Queues[exchange].Add(queueName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex.Message);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
~Receiver() => Dispose();
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_connection.Dispose();
|
||||||
|
_channel.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
dozorova_alena_lab_4/EmitLog/EmitLog..csproj
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<RootNamespace>EmitLog_</RootNamespace>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
24
dozorova_alena_lab_4/EmitLog/Program.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using System.Text;
|
||||||
|
using RabbitMQ.Client;
|
||||||
|
|
||||||
|
var factory = new ConnectionFactory { HostName = "localhost" };
|
||||||
|
using var connection = factory.CreateConnection();
|
||||||
|
using var channel = connection.CreateModel();
|
||||||
|
|
||||||
|
channel.ExchangeDeclare(exchange: "logs", type: ExchangeType.Fanout);
|
||||||
|
|
||||||
|
var message = GetMessage(args);
|
||||||
|
var body = Encoding.UTF8.GetBytes(message);
|
||||||
|
channel.BasicPublish(exchange: "logs",
|
||||||
|
routingKey: string.Empty,
|
||||||
|
basicProperties: null,
|
||||||
|
body: body);
|
||||||
|
Console.WriteLine($" [x] Sent {message}");
|
||||||
|
|
||||||
|
Console.WriteLine(" Press [enter] to exit.");
|
||||||
|
Console.ReadLine();
|
||||||
|
|
||||||
|
static string GetMessage(string[] args)
|
||||||
|
{
|
||||||
|
return ((args.Length > 0) ? string.Join(" ", args) : "info: Hello World!");
|
||||||
|
}
|
14
dozorova_alena_lab_4/NewTask/NewTask.csproj
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
32
dozorova_alena_lab_4/NewTask/Program.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
using System.Text;
|
||||||
|
using RabbitMQ.Client;
|
||||||
|
|
||||||
|
var factory = new ConnectionFactory { HostName = "localhost" };
|
||||||
|
using var connection = factory.CreateConnection();
|
||||||
|
using var channel = connection.CreateModel();
|
||||||
|
|
||||||
|
channel.QueueDeclare(queue: "task_queue",
|
||||||
|
durable: true,
|
||||||
|
exclusive: false,
|
||||||
|
autoDelete: false,
|
||||||
|
arguments: null);
|
||||||
|
|
||||||
|
var message = GetMessage(args);
|
||||||
|
var body = Encoding.UTF8.GetBytes(message);
|
||||||
|
|
||||||
|
var properties = channel.CreateBasicProperties();
|
||||||
|
properties.Persistent = true;
|
||||||
|
|
||||||
|
channel.BasicPublish(exchange: string.Empty,
|
||||||
|
routingKey: "task_queue",
|
||||||
|
basicProperties: properties,
|
||||||
|
body: body);
|
||||||
|
Console.WriteLine($" [x] Sent {message}");
|
||||||
|
|
||||||
|
Console.WriteLine(" Press [enter] to exit.");
|
||||||
|
Console.ReadLine();
|
||||||
|
|
||||||
|
static string GetMessage(string[] args)
|
||||||
|
{
|
||||||
|
return ((args.Length > 0) ? string.Join(" ", args) : "Hello World!");
|
||||||
|
}
|
30
dozorova_alena_lab_4/Publisher/.dockerignore
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
**/.classpath
|
||||||
|
**/.dockerignore
|
||||||
|
**/.env
|
||||||
|
**/.git
|
||||||
|
**/.gitignore
|
||||||
|
**/.project
|
||||||
|
**/.settings
|
||||||
|
**/.toolstarget
|
||||||
|
**/.vs
|
||||||
|
**/.vscode
|
||||||
|
**/*.*proj.user
|
||||||
|
**/*.dbmdl
|
||||||
|
**/*.jfm
|
||||||
|
**/azds.yaml
|
||||||
|
**/bin
|
||||||
|
**/charts
|
||||||
|
**/docker-compose*
|
||||||
|
**/Dockerfile*
|
||||||
|
**/node_modules
|
||||||
|
**/npm-debug.log
|
||||||
|
**/obj
|
||||||
|
**/secrets.dev.yaml
|
||||||
|
**/values.dev.yaml
|
||||||
|
LICENSE
|
||||||
|
README.md
|
||||||
|
!**/.gitignore
|
||||||
|
!.git/HEAD
|
||||||
|
!.git/config
|
||||||
|
!.git/packed-refs
|
||||||
|
!.git/refs/heads/**
|
20
dozorova_alena_lab_4/Publisher/Dockerfile
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||||
|
ARG BUILD_CONFIGURATION=Release
|
||||||
|
WORKDIR /src
|
||||||
|
COPY ["Publisher.csproj", "."]
|
||||||
|
RUN dotnet restore "./Publisher.csproj"
|
||||||
|
COPY . .
|
||||||
|
WORKDIR "/src/."
|
||||||
|
RUN dotnet build "./Publisher.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
||||||
|
|
||||||
|
FROM build AS publish
|
||||||
|
ARG BUILD_CONFIGURATION=Release
|
||||||
|
RUN dotnet publish "./Publisher.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
||||||
|
|
||||||
|
FROM base AS final
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=publish /app/publish .
|
||||||
|
ENTRYPOINT ["dotnet", "Publisher.dll"]
|
40
dozorova_alena_lab_4/Publisher/Program.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
using Publisher;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
var rabbitHost = Environment.GetEnvironmentVariable("RABBIT_HOST") ?? "localhost";
|
||||||
|
var rabbitUsername = Environment.GetEnvironmentVariable("RABBIT_USERNAME") ?? "user";
|
||||||
|
var rabbitPassword = Environment.GetEnvironmentVariable("RABBIT_PASSWORD") ?? "password";
|
||||||
|
var rabbitExchange = Environment.GetEnvironmentVariable("RABBIT_EXCHANGE") ?? "ReportIn";
|
||||||
|
|
||||||
|
var sender = new Sender(rabbitHost, rabbitUsername, rabbitPassword);
|
||||||
|
|
||||||
|
sender.AddExcange(rabbitExchange);
|
||||||
|
|
||||||
|
var rnd = new Random();
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new();
|
||||||
|
|
||||||
|
var type = rnd.Next();
|
||||||
|
switch (type%2)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
sb.Append($"Был запрошен отчет о данных под номером {rnd.Next(1000)}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
sb.Append($"Был запрошен отчет об ошибках под номером {rnd.Next(1000)}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var text = sb.ToString();
|
||||||
|
Console.WriteLine($"Было опубликовано сообщение: {text}");
|
||||||
|
sender.PublishToExchange(rabbitExchange, text);
|
||||||
|
|
||||||
|
await Task.Delay(1000);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"Publisher": {
|
||||||
|
"commandName": "Project"
|
||||||
|
},
|
||||||
|
"Container (Dockerfile)": {
|
||||||
|
"commandName": "Docker"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
dozorova_alena_lab_4/Publisher/Publisher.csproj
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
|
<DockerfileContext>.</DockerfileContext>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1" />
|
||||||
|
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
9
dozorova_alena_lab_4/Publisher/Publisher.csproj.user
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ActiveDebugProfile>Container (Dockerfile)</ActiveDebugProfile>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
25
dozorova_alena_lab_4/Publisher/Publisher.sln
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.10.35004.147
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Publisher", "Publisher.csproj", "{C23890FA-A4DD-4E5B-897F-37210C2F60CE}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{C23890FA-A4DD-4E5B-897F-37210C2F60CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C23890FA-A4DD-4E5B-897F-37210C2F60CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C23890FA-A4DD-4E5B-897F-37210C2F60CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C23890FA-A4DD-4E5B-897F-37210C2F60CE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {3BB20EB3-DE49-46CE-8C7A-D956E3DE90BC}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
69
dozorova_alena_lab_4/Publisher/Sender.cs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
using RabbitMQ.Client;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Publisher
|
||||||
|
{
|
||||||
|
public class Sender : IDisposable
|
||||||
|
{
|
||||||
|
private readonly ConnectionFactory _connectionFactory;
|
||||||
|
private readonly IConnection _connection;
|
||||||
|
private readonly IModel _channel;
|
||||||
|
|
||||||
|
public HashSet<string> Exchanges { get; private set; } = new HashSet<string>();
|
||||||
|
|
||||||
|
public Sender(string brockerHost, string brockerUsername, string brockerPassword)
|
||||||
|
{
|
||||||
|
_connectionFactory = new ConnectionFactory() { HostName = brockerHost, UserName = brockerUsername, Password = brockerPassword };
|
||||||
|
_connection = _connectionFactory.CreateConnection();
|
||||||
|
_channel = _connection.CreateModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AddExcange(string exchange, string exchangeType = ExchangeType.Fanout)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_channel.ExchangeDeclare(exchange, exchangeType);
|
||||||
|
Exchanges.Add(exchange);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex.Message);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool PublishToExchange(string exchange, string message)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!Exchanges.Contains(exchange))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var messageBody = Encoding.UTF8.GetBytes(message);
|
||||||
|
_channel.BasicPublish(exchange: exchange,
|
||||||
|
routingKey: string.Empty,
|
||||||
|
basicProperties: null,
|
||||||
|
body: messageBody);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex.Message);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
~Sender() => Dispose();
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_connection.Dispose();
|
||||||
|
_channel.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
dozorova_alena_lab_4/README.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Лабораторная работа 4
|
||||||
|
В рамках данной работы были реализованы несколько проектов, работающих с RabbitMQ.
|
||||||
|
## tutorial
|
||||||
|
Для каждого урока были созданы консольные проекты
|
||||||
|
### "Hello World!"
|
||||||
|
![Task 1](image-4.png)
|
||||||
|
### Work Queues
|
||||||
|
![Task 2](image-5.png)
|
||||||
|
### Publish/Subscribe
|
||||||
|
![Task 3](image-6.png)
|
||||||
|
## Описание
|
||||||
|
В качестве предметной области была выбрана система запросов отчета двух видов: отчета и ошибок.
|
||||||
|
## Запуск
|
||||||
|
Для запуска лабораторной работы необходимо иметь запущенный Docker на устройстве.
|
||||||
|
Необходимо перейти в папку, где располагается данный файл. Далее открыть терминал и ввести команду:
|
||||||
|
```
|
||||||
|
docker compose up -d --build
|
||||||
|
```
|
||||||
|
Порты для RabbitMQ были 8081 (для UI) и 5672.
|
||||||
|
## Анализ
|
||||||
|
Первоначальный вариант запуска предполагает, что имеется всего 2 потребителя:
|
||||||
|
1. Тратит на обработку сообщения 2-3 секунды
|
||||||
|
2. Тратит на обработку сообщения крайне малое время
|
||||||
|
Задержка при обработке понижает пропускную способность обработчика, что вызывает переполнение очереди. Это подтверждается скринами.
|
||||||
|
<br/>
|
||||||
|
![alt text](image.png)
|
||||||
|
<br/>
|
||||||
|
![alt text](image-1.png)
|
||||||
|
<br/>
|
||||||
|
Теперь запустим несколько обычных обработчиков. Очередь не переполнена постоянно, а периодически, соответственно обработчики вполне справляются с потоком сообщений и увеличение их количества позволит в принципе избавиться от переполнения
|
||||||
|
<br/>
|
||||||
|
![alt text](image-2.png)
|
||||||
|
<br/>
|
||||||
|
![alt text](image-3.png)
|
||||||
|
|
||||||
|
## Видеодемонстрация
|
||||||
|
Демонстрация: (https://drive.google.com/file/d/16gJMGbMKSFZ_I5gCzuDekpAqUrhbpFRA/view?usp=sharing) Стоит обратить внимание на то, что настройки docker compose файла не гарантируют верный порядок подъема контейнеров, из-за чего некоторые контейнеры пришлось перезапустить.
|
||||||
|
|
||||||
|
|
29
dozorova_alena_lab_4/Receive/Program.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
using System.Text;
|
||||||
|
using RabbitMQ.Client;
|
||||||
|
using RabbitMQ.Client.Events;
|
||||||
|
|
||||||
|
var factory = new ConnectionFactory { HostName = "localhost" };
|
||||||
|
using var connection = factory.CreateConnection();
|
||||||
|
using var channel = connection.CreateModel();
|
||||||
|
|
||||||
|
channel.QueueDeclare(queue: "hello",
|
||||||
|
durable: false,
|
||||||
|
exclusive: false,
|
||||||
|
autoDelete: false,
|
||||||
|
arguments: null);
|
||||||
|
|
||||||
|
Console.WriteLine(" [*] Waiting for messages.");
|
||||||
|
|
||||||
|
var consumer = new EventingBasicConsumer(channel);
|
||||||
|
consumer.Received += (model, ea) =>
|
||||||
|
{
|
||||||
|
var body = ea.Body.ToArray();
|
||||||
|
var message = Encoding.UTF8.GetString(body);
|
||||||
|
Console.WriteLine($" [x] Received {message}");
|
||||||
|
};
|
||||||
|
channel.BasicConsume(queue: "hello",
|
||||||
|
autoAck: true,
|
||||||
|
consumer: consumer);
|
||||||
|
|
||||||
|
Console.WriteLine(" Press [enter] to exit.");
|
||||||
|
Console.ReadLine();
|
14
dozorova_alena_lab_4/Receive/Receive.csproj
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
31
dozorova_alena_lab_4/ReceiveLogs/Program.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using System.Text;
|
||||||
|
using RabbitMQ.Client;
|
||||||
|
using RabbitMQ.Client.Events;
|
||||||
|
|
||||||
|
var factory = new ConnectionFactory { HostName = "localhost" };
|
||||||
|
using var connection = factory.CreateConnection();
|
||||||
|
using var channel = connection.CreateModel();
|
||||||
|
|
||||||
|
channel.ExchangeDeclare(exchange: "logs", type: ExchangeType.Fanout);
|
||||||
|
|
||||||
|
// declare a server-named queue
|
||||||
|
var queueName = channel.QueueDeclare().QueueName;
|
||||||
|
channel.QueueBind(queue: queueName,
|
||||||
|
exchange: "logs",
|
||||||
|
routingKey: string.Empty);
|
||||||
|
|
||||||
|
Console.WriteLine(" [*] Waiting for logs.");
|
||||||
|
|
||||||
|
var consumer = new EventingBasicConsumer(channel);
|
||||||
|
consumer.Received += (model, ea) =>
|
||||||
|
{
|
||||||
|
byte[] body = ea.Body.ToArray();
|
||||||
|
var message = Encoding.UTF8.GetString(body);
|
||||||
|
Console.WriteLine($" [x] {message}");
|
||||||
|
};
|
||||||
|
channel.BasicConsume(queue: queueName,
|
||||||
|
autoAck: true,
|
||||||
|
consumer: consumer);
|
||||||
|
|
||||||
|
Console.WriteLine(" Press [enter] to exit.");
|
||||||
|
Console.ReadLine();
|
14
dozorova_alena_lab_4/ReceiveLogs/ReceiveLogs.csproj
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
24
dozorova_alena_lab_4/Send/Program.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using System.Text;
|
||||||
|
using RabbitMQ.Client;
|
||||||
|
|
||||||
|
var factory = new ConnectionFactory { HostName = "localhost" };
|
||||||
|
using var connection = factory.CreateConnection();
|
||||||
|
using var channel = connection.CreateModel();
|
||||||
|
|
||||||
|
channel.QueueDeclare(queue: "hello",
|
||||||
|
durable: false,
|
||||||
|
exclusive: false,
|
||||||
|
autoDelete: false,
|
||||||
|
arguments: null);
|
||||||
|
|
||||||
|
const string message = "Hello World!";
|
||||||
|
var body = Encoding.UTF8.GetBytes(message);
|
||||||
|
|
||||||
|
channel.BasicPublish(exchange: string.Empty,
|
||||||
|
routingKey: "hello",
|
||||||
|
basicProperties: null,
|
||||||
|
body: body);
|
||||||
|
Console.WriteLine($" [x] Sent {message}");
|
||||||
|
|
||||||
|
Console.WriteLine(" Press [enter] to exit.");
|
||||||
|
Console.ReadLine();
|
14
dozorova_alena_lab_4/Send/Send.csproj
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
39
dozorova_alena_lab_4/Worker/Program.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
using System.Text;
|
||||||
|
using RabbitMQ.Client;
|
||||||
|
using RabbitMQ.Client.Events;
|
||||||
|
|
||||||
|
var factory = new ConnectionFactory { HostName = "localhost" };
|
||||||
|
using var connection = factory.CreateConnection();
|
||||||
|
using var channel = connection.CreateModel();
|
||||||
|
|
||||||
|
channel.QueueDeclare(queue: "task_queue",
|
||||||
|
durable: true,
|
||||||
|
exclusive: false,
|
||||||
|
autoDelete: false,
|
||||||
|
arguments: null);
|
||||||
|
|
||||||
|
channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
|
||||||
|
|
||||||
|
Console.WriteLine(" [*] Waiting for messages.");
|
||||||
|
|
||||||
|
var consumer = new EventingBasicConsumer(channel);
|
||||||
|
consumer.Received += (model, ea) =>
|
||||||
|
{
|
||||||
|
byte[] body = ea.Body.ToArray();
|
||||||
|
var message = Encoding.UTF8.GetString(body);
|
||||||
|
Console.WriteLine($" [x] Received {message}");
|
||||||
|
|
||||||
|
int dots = message.Split('.').Length - 1;
|
||||||
|
Thread.Sleep(dots * 1000);
|
||||||
|
|
||||||
|
Console.WriteLine(" [x] Done");
|
||||||
|
|
||||||
|
// here channel could also be accessed as ((EventingBasicConsumer)sender).Model
|
||||||
|
channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
|
||||||
|
};
|
||||||
|
channel.BasicConsume(queue: "task_queue",
|
||||||
|
autoAck: false,
|
||||||
|
consumer: consumer);
|
||||||
|
|
||||||
|
Console.WriteLine(" Press [enter] to exit.");
|
||||||
|
Console.ReadLine();
|
14
dozorova_alena_lab_4/Worker/Worker.csproj
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
59
dozorova_alena_lab_4/docker-compose.yaml
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
services:
|
||||||
|
rabbit:
|
||||||
|
image: rabbitmq:3.10.7-management
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- 5672:5672
|
||||||
|
- 8081:15672
|
||||||
|
environment:
|
||||||
|
RABBITMQ_DEFAULT_USER: admin
|
||||||
|
RABBITMQ_DEFAULT_PASS: admin
|
||||||
|
|
||||||
|
publisher:
|
||||||
|
build: ./Publisher/
|
||||||
|
restart: always
|
||||||
|
depends_on:
|
||||||
|
- rabbit
|
||||||
|
environment:
|
||||||
|
RABBIT_HOST: rabbit
|
||||||
|
RABBIT_USERNAME: admin
|
||||||
|
RABBIT_PASSWORD: admin
|
||||||
|
RABBIT_EXCHANGE: 'ReportIn'
|
||||||
|
|
||||||
|
concumer1:
|
||||||
|
build: ./ConsumerSimple/
|
||||||
|
restart: always
|
||||||
|
depends_on:
|
||||||
|
- rabbit
|
||||||
|
- publisher
|
||||||
|
environment:
|
||||||
|
RABBIT_HOST: rabbit
|
||||||
|
RABBIT_USERNAME: admin
|
||||||
|
RABBIT_PASSWORD: admin
|
||||||
|
RABBIT_EXCHANGE: 'ReportIn'
|
||||||
|
RABBIT_QUEUE: 'First'
|
||||||
|
|
||||||
|
concumer2:
|
||||||
|
build: ./ConsumerSimple/
|
||||||
|
restart: always
|
||||||
|
depends_on:
|
||||||
|
- rabbit
|
||||||
|
- publisher
|
||||||
|
environment:
|
||||||
|
RABBIT_HOST: rabbit
|
||||||
|
RABBIT_USERNAME: admin
|
||||||
|
RABBIT_PASSWORD: admin
|
||||||
|
RABBIT_EXCHANGE: 'ReportIn'
|
||||||
|
RABBIT_QUEUE: 'Second'
|
||||||
|
# concumer2:
|
||||||
|
# build: ./ConsumerDelay/
|
||||||
|
# restart: always
|
||||||
|
# depends_on:
|
||||||
|
# - rabbit
|
||||||
|
# - publisher
|
||||||
|
# environment:
|
||||||
|
# RABBIT_HOST: rabbit
|
||||||
|
# RABBIT_USERNAME: admin
|
||||||
|
# RABBIT_PASSWORD: admin
|
||||||
|
# RABBIT_EXCHANGE: 'ReportIn'
|
||||||
|
# RABBIT_QUEUE: 'Second'
|
BIN
dozorova_alena_lab_4/image-1.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
dozorova_alena_lab_4/image-2.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
dozorova_alena_lab_4/image-3.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
dozorova_alena_lab_4/image-4.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
dozorova_alena_lab_4/image-5.png
Normal file
After Width: | Height: | Size: 136 KiB |
BIN
dozorova_alena_lab_4/image-6.png
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
dozorova_alena_lab_4/image.png
Normal file
After Width: | Height: | Size: 16 KiB |
26
dozorova_alena_lab_5/.gitignore
vendored
@ -10,3 +10,29 @@
|
|||||||
/dozorova_alena_lab_5/ConsoleApp1/.vs
|
/dozorova_alena_lab_5/ConsoleApp1/.vs
|
||||||
/dozorova_alena_lab_5/ConsoleApp1/bin
|
/dozorova_alena_lab_5/ConsoleApp1/bin
|
||||||
/dozorova_alena_lab_5/ConsoleApp1/obj
|
/dozorova_alena_lab_5/ConsoleApp1/obj
|
||||||
|
/dozorova_alena_lab_3/PostService/.vs
|
||||||
|
/dozorova_alena_lab_3/WorkerService/.vs
|
||||||
|
/dozorova_alena_lab_4/Receive/bin
|
||||||
|
/dozorova_alena_lab_4/Receive/obj
|
||||||
|
/dozorova_alena_lab_4/Send/bin
|
||||||
|
/dozorova_alena_lab_4/Send/obj
|
||||||
|
/dozorova_alena_lab_4/EmitLog/.vs
|
||||||
|
/dozorova_alena_lab_4/EmitLog/obj
|
||||||
|
/dozorova_alena_lab_4/NewTask/.vs
|
||||||
|
/dozorova_alena_lab_4/NewTask/bin
|
||||||
|
/dozorova_alena_lab_4/NewTask/obj
|
||||||
|
/dozorova_alena_lab_4/ReceiveLogs/obj
|
||||||
|
/dozorova_alena_lab_4/Worker/.vs
|
||||||
|
/dozorova_alena_lab_4/Worker/bin
|
||||||
|
/dozorova_alena_lab_4/Worker/obj
|
||||||
|
/dozorova_alena_lab_4/EmitLog/bin
|
||||||
|
/dozorova_alena_lab_4/ReceiveLogs/.vs
|
||||||
|
/dozorova_alena_lab_4/ReceiveLogs/bin
|
||||||
|
/dozorova_alena_lab_4/ConsumerDelay/.vs
|
||||||
|
/dozorova_alena_lab_4/ConsumerDelay/obj
|
||||||
|
/dozorova_alena_lab_4/ConsumerDelay/Properties
|
||||||
|
/dozorova_alena_lab_4/ConsumerSimple/.vs
|
||||||
|
/dozorova_alena_lab_4/ConsumerSimple/obj
|
||||||
|
/dozorova_alena_lab_4/Publisher/.vs
|
||||||
|
/dozorova_alena_lab_4/Publisher/bin
|
||||||
|
/dozorova_alena_lab_4/Publisher/objs
|
||||||
|
5
kalyshev_yan_lab_2/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
data/
|
||||||
|
result/
|
||||||
|
result_first/
|
||||||
|
result_second/
|
||||||
|
datagen.py
|
16
kalyshev_yan_lab_2/FirstProgram/Dockerfile
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#Берем базовый образ python
|
||||||
|
FROM python:3.12
|
||||||
|
|
||||||
|
#Устанавливаем рабочую директорию
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
#Копирум код в рабочую директорию
|
||||||
|
COPY main.py .
|
||||||
|
|
||||||
|
#Задаем /var/data как монтируемый
|
||||||
|
VOLUME ["/var/data"]
|
||||||
|
#Задаем /var/result как монтируемый
|
||||||
|
VOLUME ["/var/result"]
|
||||||
|
|
||||||
|
#Задаем команду для выполнения программы
|
||||||
|
CMD ["python", "main.py"]
|
79
kalyshev_yan_lab_2/FirstProgram/main.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import os
|
||||||
|
import random
|
||||||
|
|
||||||
|
# Установите полный путь к каталогу, в котором нужно искать самый большой файл.
|
||||||
|
CATALOG_PATH = "/var/data"
|
||||||
|
|
||||||
|
# Полный путь до файла результата.
|
||||||
|
RESULT_FILE = "/var/result/data.txt"
|
||||||
|
|
||||||
|
|
||||||
|
def find_largest_file(directory):
|
||||||
|
"""Ищет самый большой по объему файл в заданном каталоге и его подкаталогах."""
|
||||||
|
|
||||||
|
largest_file = None
|
||||||
|
max_size = 0
|
||||||
|
|
||||||
|
for root, _, files in os.walk(directory):
|
||||||
|
for file in files:
|
||||||
|
# Полный путь к текущему файлу.
|
||||||
|
filepath = os.path.join(root, file)
|
||||||
|
|
||||||
|
try:
|
||||||
|
file_size = os.stat(filepath).st_size
|
||||||
|
|
||||||
|
if file_size > max_size:
|
||||||
|
max_size = file_size
|
||||||
|
largest_file = (filepath, file_size)
|
||||||
|
|
||||||
|
except OSError as e:
|
||||||
|
print(f"Ошибка при открытии файла '{filepath}': {e}")
|
||||||
|
|
||||||
|
return largest_file
|
||||||
|
|
||||||
|
|
||||||
|
def copy_file(src, dst):
|
||||||
|
"""Копирует содержимое файла src в файл dst."""
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(dst, "wb") as f_dst, open(src, "rb") as f_src:
|
||||||
|
while chunk := f_src.read(4096):
|
||||||
|
f_dst.write(chunk)
|
||||||
|
|
||||||
|
print(f"Файл '{src}' успешно скопирован в '{dst}'.")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Ошибка при копировании файла '{src}': {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
largest_file_path = find_largest_file(CATALOG_PATH)
|
||||||
|
|
||||||
|
if largest_file_path:
|
||||||
|
src_path, _ = largest_file_path
|
||||||
|
dst_path = RESULT_FILE
|
||||||
|
|
||||||
|
copy_file(src_path, dst_path)
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("Нет файлов в каталоге.")
|
||||||
|
|
||||||
|
|
||||||
|
def generate_random_numbers(filename, count):
|
||||||
|
"""Функция генерирует случайные числа и записывает их в файл."""
|
||||||
|
|
||||||
|
with open(filename, "w") as f:
|
||||||
|
for _ in range(count):
|
||||||
|
num = random.randint(0, 1000)
|
||||||
|
f.write(str(num) + "\n")
|
||||||
|
|
||||||
|
print(f"Случайные числа успешно записаны в '{filename}'.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
generate_random_numbers("/var/data/data1.txt", 50)
|
||||||
|
generate_random_numbers("/var/data/data2.txt", 75)
|
||||||
|
generate_random_numbers("/var/data/data3.txt", 25)
|
||||||
|
print("Генерация файлов завершена.")
|
||||||
|
|
||||||
|
main()
|
74
kalyshev_yan_lab_2/README.md
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
# Калышев Ян ПИбд-42
|
||||||
|
|
||||||
|
## Описание
|
||||||
|
|
||||||
|
Этот проект предоставляет 2 контейнера с простыми python-скриптами такими, что результат первого является исходными данными для второго.
|
||||||
|
|
||||||
|
## 1. Варианты
|
||||||
|
|
||||||
|
Для первой программы был взят вариант:
|
||||||
|
**0**. Ищет в каталоге /var/data самый большой по объёму файл и перекладывает его в /var/result/data.txt.
|
||||||
|
|
||||||
|
Для второй программы был взят вариант:
|
||||||
|
**2**. Ищет наименьшее число из файла /var/data/data.txt и сохраняет его третью степень в /var/result/result.txt.
|
||||||
|
|
||||||
|
## 2. Структура Dockerfile
|
||||||
|
|
||||||
|
Оба Dockerfile почти одинаковые:
|
||||||
|
|
||||||
|
```Dockerfile
|
||||||
|
#Берем базовый образ python
|
||||||
|
FROM python:3.12
|
||||||
|
|
||||||
|
#Устанавливаем рабочую директорию
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
#Копирум код в рабочую директорию
|
||||||
|
COPY main.py .
|
||||||
|
|
||||||
|
#Задаем /var/data как монтируемый
|
||||||
|
VOLUME ["/var/data"]
|
||||||
|
#Задаем /var/result как монтируемый
|
||||||
|
VOLUME ["/var/result"]
|
||||||
|
|
||||||
|
#Задаем команду для выполнения программы
|
||||||
|
CMD ["python", "main.py"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Docker Compose
|
||||||
|
|
||||||
|
`docker-compose.yml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
#Первый скрипт
|
||||||
|
first:
|
||||||
|
#Указание директории для сборки первого скрипта
|
||||||
|
build: ./FirstProgram/
|
||||||
|
#Монтирование 2 каталогов из хост системы
|
||||||
|
volumes:
|
||||||
|
- ./data:/var/data
|
||||||
|
- ./result_first:/var/result
|
||||||
|
|
||||||
|
#Второй скрипт
|
||||||
|
second:
|
||||||
|
#Указание директории для сборки второго скрипта
|
||||||
|
build: ./SecondProgram/
|
||||||
|
#Задание очередности запуска с помощью depends_on
|
||||||
|
depends_on:
|
||||||
|
- first
|
||||||
|
#Монтирование 2 каталогов из хост системы
|
||||||
|
volumes:
|
||||||
|
- ./result_first:/var/data
|
||||||
|
- ./result_second:/var/result
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Запуск
|
||||||
|
|
||||||
|
Для запуска использовать команду `docker compose up --build`
|
||||||
|
Предварительно нужно создать папку `data`, в которой создать файлы, где каждая строка - это число.
|
||||||
|
Результат первого скрипта будет в папке `result_first`, результат второго скрипта будет в папке `result_second`.
|
||||||
|
|
||||||
|
## 7. Ссылка на видео
|
||||||
|
|
||||||
|
[Видео-отчёт Калышев Ян ПИбд-42](https://zyzf.space/s/65HRyTTXAzxpwBF)
|
16
kalyshev_yan_lab_2/SecondProgram/Dockerfile
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#Берем базовый образ python
|
||||||
|
FROM python:3.12
|
||||||
|
|
||||||
|
#Устанавливаем рабочую директорию
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
#Копирум код в рабочую директорию
|
||||||
|
COPY main.py .
|
||||||
|
|
||||||
|
#Задаем /var/data как монтируемый
|
||||||
|
VOLUME ["/var/data"]
|
||||||
|
#Задаем /var/result как монтируемый
|
||||||
|
VOLUME ["/var/result"]
|
||||||
|
|
||||||
|
#Задаем команду для выполнения программы
|
||||||
|
CMD ["python", "main.py"]
|
60
kalyshev_yan_lab_2/SecondProgram/main.py
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
# Установите полный путь к файлу, из которого нужно читать числа.
|
||||||
|
DATA_FILE = "/var/data/data.txt"
|
||||||
|
|
||||||
|
# Полный путь до файла результата.
|
||||||
|
RESULT_FILE = "/var/result/result.txt"
|
||||||
|
|
||||||
|
|
||||||
|
def find_smallest_number(data_file):
|
||||||
|
"""Ищет наименьшее число в заданном файле."""
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(data_file, "r") as f:
|
||||||
|
numbers = [int(line.strip()) for line in f.readlines()]
|
||||||
|
|
||||||
|
smallest_num = min(numbers)
|
||||||
|
return smallest_num
|
||||||
|
|
||||||
|
except ValueError as e:
|
||||||
|
print(f"Ошибка при преобразовании строк в числа: {e}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Ошибка чтения файла '{data_file}': {e}")
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def cube_number(num):
|
||||||
|
"""Возвращает куб заданного числа."""
|
||||||
|
|
||||||
|
return num**3
|
||||||
|
|
||||||
|
|
||||||
|
def write_result(result_file, result):
|
||||||
|
"""Записывает результат в файл."""
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(result_file, "w") as f:
|
||||||
|
f.write(str(result))
|
||||||
|
|
||||||
|
print(f"Результат '{result}' успешно записан в '{result_file}'.")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Ошибка записи результата в файл '{result_file}': {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
smallest_num = find_smallest_number(DATA_FILE)
|
||||||
|
|
||||||
|
if smallest_num is not None:
|
||||||
|
result = cube_number(smallest_num)
|
||||||
|
|
||||||
|
write_result(RESULT_FILE, result)
|
||||||
|
print(result)
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("Нет чисел в файле.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
21
kalyshev_yan_lab_2/docker-compose.yml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
services:
|
||||||
|
#Первый скрипт
|
||||||
|
first:
|
||||||
|
#Указание директории для сборки первого скрипта
|
||||||
|
build: ./FirstProgram/
|
||||||
|
#Монтирование 2 каталогов из хост системы
|
||||||
|
volumes:
|
||||||
|
- ./data:/var/data
|
||||||
|
- ./result_first:/var/result
|
||||||
|
|
||||||
|
#Второй скрипт
|
||||||
|
second:
|
||||||
|
#Указание директории для сборки второго скрипта
|
||||||
|
build: ./SecondProgram/
|
||||||
|
#Задание очередности запуска с помощью depends_on
|
||||||
|
depends_on:
|
||||||
|
- first
|
||||||
|
#Монтирование 2 каталогов из хост системы
|
||||||
|
volumes:
|
||||||
|
- ./result_first:/var/data
|
||||||
|
- ./result_second:/var/result
|
484
kuzarin_maxim_lab_5/.gitignore
vendored
Normal file
@ -0,0 +1,484 @@
|
|||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from `dotnet new gitignore`
|
||||||
|
|
||||||
|
# dotenv files
|
||||||
|
.env
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# Tye
|
||||||
|
.tye/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.tlog
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
||||||
|
*.vbp
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
||||||
|
*.dsw
|
||||||
|
*.dsp
|
||||||
|
|
||||||
|
# Visual Studio 6 technical files
|
||||||
|
*.ncb
|
||||||
|
*.aps
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# Visual Studio History (VSHistory) files
|
||||||
|
.vshistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
||||||
|
|
||||||
|
# VS Code files for those working on multiple tools
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
.history/
|
||||||
|
|
||||||
|
# Windows Installer files from build outputs
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
*.sln.iml
|
||||||
|
.idea
|
||||||
|
|
||||||
|
##
|
||||||
|
## Visual studio for Mac
|
||||||
|
##
|
||||||
|
|
||||||
|
|
||||||
|
# globs
|
||||||
|
Makefile.in
|
||||||
|
*.userprefs
|
||||||
|
*.usertasks
|
||||||
|
config.make
|
||||||
|
config.status
|
||||||
|
aclocal.m4
|
||||||
|
install-sh
|
||||||
|
autom4te.cache/
|
||||||
|
*.tar.gz
|
||||||
|
tarballs/
|
||||||
|
test-results/
|
||||||
|
|
||||||
|
# Mac bundle stuff
|
||||||
|
*.dmg
|
||||||
|
*.app
|
||||||
|
|
||||||
|
# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
|
||||||
|
# General
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
|
||||||
|
# Windows thumbnail cache files
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
|
||||||
|
# Dump file
|
||||||
|
*.stackdump
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
[Dd]esktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Windows shortcuts
|
||||||
|
*.lnk
|
||||||
|
|
||||||
|
# Vim temporary swap files
|
||||||
|
*.swp
|
BIN
kuzarin_maxim_lab_5/Images/Resouts.png
Normal file
After Width: | Height: | Size: 31 KiB |
25
kuzarin_maxim_lab_5/MatrixMultiplication.sln
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.10.34916.146
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatrixMultiplication", "MatrixMultiplication\MatrixMultiplication.csproj", "{EF2DB216-9BCD-4FEE-B9C8-4262A5B7CC30}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{EF2DB216-9BCD-4FEE-B9C8-4262A5B7CC30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{EF2DB216-9BCD-4FEE-B9C8-4262A5B7CC30}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{EF2DB216-9BCD-4FEE-B9C8-4262A5B7CC30}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{EF2DB216-9BCD-4FEE-B9C8-4262A5B7CC30}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {619485C2-FE35-496B-9E25-4F5465D0C1A1}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
@ -0,0 +1,10 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
117
kuzarin_maxim_lab_5/MatrixMultiplication/Program.cs
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
internal class Program
|
||||||
|
{
|
||||||
|
private static string[] _resTableColumnsNames = new string[] { "m*m", "1 t", "2 t", "3 t", "4 t", "5 t", "6 t", "7 t", "8 t" };
|
||||||
|
|
||||||
|
private static void Main(string[] args)
|
||||||
|
{
|
||||||
|
Console.WriteLine(string.Join("\t", _resTableColumnsNames));
|
||||||
|
|
||||||
|
for (int i = 10; i < 10000; i *= 2)
|
||||||
|
{
|
||||||
|
var a = CreateMatrix(i, i);
|
||||||
|
var b = CreateMatrix(i, i);
|
||||||
|
|
||||||
|
List<long> times = new() { i };
|
||||||
|
|
||||||
|
for (int j = 1; j <= 8; j++)
|
||||||
|
{
|
||||||
|
var sw = new Stopwatch();
|
||||||
|
sw.Start();
|
||||||
|
|
||||||
|
MultiplyMatrix(a, b, j);
|
||||||
|
|
||||||
|
sw.Stop();
|
||||||
|
times.Add(sw.ElapsedMilliseconds);
|
||||||
|
}
|
||||||
|
Console.WriteLine(string.Join("\t", times));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Создаём матрицу случайных элементов
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x"></param>
|
||||||
|
/// <param name="y"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static int[,] CreateMatrix(int x, int y)
|
||||||
|
{
|
||||||
|
var rnd = new Random();
|
||||||
|
|
||||||
|
var res = new int[y, x];
|
||||||
|
|
||||||
|
for (int i = 0; i < y; i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < x; j++)
|
||||||
|
{
|
||||||
|
res[i, j] = rnd.Next(0, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Вывести матрицу. Использовался при отладке
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mx"></param>
|
||||||
|
private static void PrintMatrix(int[,] mx)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < mx.GetLength(0); i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < mx.GetLength(1); j++)
|
||||||
|
{
|
||||||
|
Console.Write($"{mx[i, j].ToString("000")}\t");
|
||||||
|
}
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Непосредственно умножение матриц
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a"></param>
|
||||||
|
/// <param name="b"></param>
|
||||||
|
/// <param name="maxTask"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static int[,] MultiplyMatrix(int[,] a, int[,] b, int maxTask)
|
||||||
|
{
|
||||||
|
int[,] res = new int[a.GetLength(0), b.GetLength(1)];
|
||||||
|
|
||||||
|
var semaphore = new SemaphoreSlim(maxTask, maxTask);
|
||||||
|
|
||||||
|
for (int i = 0; i < a.GetLength(0); i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < b.GetLength(1); j++)
|
||||||
|
{
|
||||||
|
semaphore.Wait();
|
||||||
|
int ci = i;
|
||||||
|
int cj = j;
|
||||||
|
_ = Task.Run(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
res[ci, cj] = CalculateElement(a, b, ci, cj);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
semaphore.Release();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
semaphore.Wait(maxTask);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Вычисление значение одного элемента
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a"></param>
|
||||||
|
/// <param name="b"></param>
|
||||||
|
/// <param name="i"></param>
|
||||||
|
/// <param name="j"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static int CalculateElement(int[,] a, int[,] b, int i, int j)
|
||||||
|
=> Enumerable.Range(0, a.GetLength(1)).Sum(k => a[i, k] * b[k, j]);
|
||||||
|
}
|
20
kuzarin_maxim_lab_5/README.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Лабораторная работа 5
|
||||||
|
Данная работа посвящена параллельному умножению больших матриц (чтобы это был побыстрее)
|
||||||
|
## Описание
|
||||||
|
Основной принцип умножения матриц: строки умножаются на столбцы, таким образом получаются элементы. И так как значения в строках/столбцах не меняется по ходу алгоритма, его достаточно легко можно распаралелить.
|
||||||
|
|
||||||
|
## Запуск
|
||||||
|
Приложение представлет собой консольную программу на C#, которую можно скомпилировать и затем запустит exe файл. В результате в окне консоли появится таблица сравнения времени умножения 2-х квадратных матриц (размер указан в первой колонке) с использованием разного числа потоков(от 1 до 8). Чем больше размер, тем дольше будет идти расчёт.
|
||||||
|
## Результаты
|
||||||
|
Результаты одного из запусков программы представлены ниже.
|
||||||
|
<br/>
|
||||||
|
![Resout](Images/Resouts.png)
|
||||||
|
<br/>
|
||||||
|
Как можно заметить, на небольших размерах распаралеливание не приносит никакого выигрыша, а иногда даже удлиняет время работы. Это связана с тем, что работы с потоками (запуск, получение результата и т. п.) - требует дополнительного времени, а из-за малого числа операций в целом, получаем не прирост производительности, а её падение.
|
||||||
|
Противоположно обстоят дела в случае с большими матрицами. Так как там расчётов значительно больше, распаралеливание начинает значительно ускорять вычисление результата. Причём, часто можно видеть, что, например, увеличения числа потоков с 1 до 2 (в 2 раза) сокращает время в 2 раза. Но чем больше потоков, тем прирост меньше (так как вновь вступают в силу факторы, описанные ранее). И прирост производительности пусть и есть, но он очень небольшой.
|
||||||
|
|
||||||
|
## Видеодемонстрация
|
||||||
|
Был записан видеоролик, демонстрирующий процесс запуска и работы системы. Он расположен по [адресу](https://drive.google.com/file/d/1dhA3JUAhhpDUh32xVW7jMuW1BKDX02eV/view?usp=sharing)
|
||||||
|
|
||||||
|
|
||||||
|
|