Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.63/8: Рейтинг темы: голосов - 8, средняя оценка - 4.63
0 / 0 / 0
Регистрация: 19.12.2022
Сообщений: 9

Смысл асинхроности в webapi

03.08.2023, 20:34. Показов 1989. Ответов 32
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Привет, простой вопрос в чем смысл асинхронности в .net web api , если и так на каждый запрос от клиента выделяется поток?
И если в этом потоке встречаем асинхронный код , то выделяется еще поток чтобы "отпустить" текущий?
Получается бессмысленно меняем поток на другой поток?!
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
03.08.2023, 20:34
Ответы с готовыми решениями:

WCF vs WebAPI
WCF умер, не родившись толком? В чем плюсы и в чем минусы соперников?

PATCH в WebApi 2
Нашел статью по этому поводу, вроде бы все предельно ясно, да вот что-то не так: гет работает, а при патч-запросе я получаю в ответ 204. ...

Steam WebApi и C#
Кто разбирается в Steam WebApi и C#, нужна помощь. Сам бот: https://github.com/Jessecar96/SteamBot Файл Schema.cs: ...

32
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
04.08.2023, 16:58
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Usaga Посмотреть сообщение
пока идёт ожидание асинхронной операции, поток её начавший, может быть отпущен назад в пул, откуда будет взят для обработки следующего запроса.
Кажись на этом тему можно было сворачивать.
0
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,775
04.08.2023, 17:30
Цитата Сообщение от kolorotur Посмотреть сообщение
На деле, конечно, асинхронная обработка при больших количествах одновременных запросов будет выигрывать у многопоточности и по времени обработки.
В общем по сути получается, что если у нас достаточно высоконагруженная система, где асинхронность даёт заметный выигрышь, то в ней есть смысл. В остальных ситуациях нет смысла замусоривать код.

Добавлено через 6 минут
Цитата Сообщение от Wolfdp Посмотреть сообщение
Кажись на этом тему можно было сворачивать.
Не, это вообще не ответ на исходный вопрос. Это просто обозначение одного из технических нюансов асинхронности. Ну возвращается в пул и что? Потоков что ли мало? Всегда можно новый создать.

А про смысл kolorotur и IamRain рассказали. Теперь хоть есть понимание, что в каких-то сценариях от асинхронности на сервере и в самом деле может быть польза.
0
 Аватар для IamRain
4694 / 2702 / 734
Регистрация: 02.08.2011
Сообщений: 7,236
04.08.2023, 17:42
Цитата Сообщение от kotelok Посмотреть сообщение
Теперь хоть есть понимание,
Асинхронность вообще довольно обширное понятие, прерывания в ОС - тоже элементы асинхронности.
Условно, мы работаем с вами в очной форме в одном офисе, и я знаю что для вас конфеты-леденцы - это топливо для работы.
И вот условно ближе к обеду, я могу подойти и подзарядить вас:
1. Синхронно - не смотря на то, что вы находитесь в состоянии потока, и допиливаете какую-то сложную логику, вот вот закончите; но я не смотря на ваше состояние потока, дергаю вас за плечо, и говорю, kotelok!! - возьми конфету! Подзарядил, но вывел из состояния потока. Все испортил.
2. Асинхронно, просто мимо проходя кинул пару-тройку леденцов вам на стол. Не отвлекая вас от ваших дел.
Внимание, вопрос: производительность какой системы будет выше?
1
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
04.08.2023, 17:47
Цитата Сообщение от kotelok Посмотреть сообщение
Потоков что ли мало? Всегда можно новый создать.
Ну как сказать...
В большинстве случаев ваша реализация сервиса будет работать в среде с IoC, т.е. обработкой запросов и той части, где принимается решение на создание нового потока будете управлять не вы, а веб-сервер, поверх которого вы пишете свои контроллеры (IIS, Kestrel и т.д.). Ваш код будет запускаться тогда, когда решение о создании нового потока или переиспользовании старого уже принято.
Насколько мне известно, эти сервера предполагают, что будет использоваться асинхронность, потому создают ограниченное количество потоков на обработку запросов. В этом случае без дополнительного ковыряния конфигов этих сервисов вариант с потоками будет работать совсем плохо.
Ну а чем ковыряться в документации и тестировать методом тыка, наверное проще прописать где нужно async и await.
1
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
04.08.2023, 18:17
Цитата Сообщение от kotelok Посмотреть сообщение
Не, это вообще не ответ на исходный вопрос
Если рассматривать как ответ на экзамене или собеседовании -- вполне себе годится. Если говорит об обучении... это тема явно не конкретно web api, а гораздо более раннего материала "многопоточность", где рассматривается зачем нужны отдельные потоки, почему этот ресурс дорогой, что есть операции ожидающие внешнего ресурса (начиная от чтения файла и заканчивая ожидание ответа от сокета), которые позволяют высвободить на время треад, что есть пулл и он не бесконечен (и при неправильном использовании позволят словит лок ВСЕГО приложения).
0
0 / 0 / 0
Регистрация: 19.12.2022
Сообщений: 9
04.08.2023, 19:46  [ТС]
Могу записать видео где я делаю Sleep и вызываю много раз, в дебаге вижу что каждый sleep будет в своём потоке с разными threadID
0
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
04.08.2023, 22:21
Цитата Сообщение от Mastodon_dev Посмотреть сообщение
Могу записать видео где я делаю Sleep и вызываю много раз, в дебаге вижу что каждый sleep будет в своём потоке с разными threadID
Эм.... спасибо, не надо. Я думаю уважаемая публика и так прекрасно понимает как работает асинхронщина.
0
0 / 0 / 0
Регистрация: 19.12.2022
Сообщений: 9
04.08.2023, 23:15  [ТС]
Wolfdp,
Миниатюры
Смысл асинхроности в webapi  
0
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
05.08.2023, 05:11
Mastodon_dev, я подозреваю что подразумевалось "не создается новый, а берется из пула". Сервак держит набор заготовленных тредов, для обработки входящих реквестов. Насколько знаю, тоже самое происходит и с ассинхронным кодом
- пришел запрос, выгребли из пулла свободный треад
- дошли скажем до запроса к БД, который асинхронный, ушел запрос
- тред за ненадобностью возращаеться в пул
- через N-милисекунд (ну или часов, тут как повезет) возращается ответ от БД. Из пулла опять выгребается свободный треад для формирования респонса клиента
0
Эксперт .NET
 Аватар для Usaga
14726 / 9496 / 1362
Регистрация: 21.01.2016
Сообщений: 35,811
05.08.2023, 07:39
Цитата Сообщение от kotelok Посмотреть сообщение
Не, это вообще не ответ на исходный вопрос. Это просто обозначение одного из технических нюансов асинхронности. Ну возвращается в пул и что? Потоков что ли мало? Всегда можно новый создать.
Новый поток требует памяти на стек. Это выше уже обозначали. Их нельзя бесконечно создавать. Но вообще, выше опять же верно заметили, что если у тебя сервис обслуживает полтора запроса в час, то наличие\отсутствие асинхронности решает ничего.
0
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
05.08.2023, 08:22
Появилось непреодолимое желание поговнокодить подтвердить свои слова кодом. А то вторая страница обсуждения и как-то грустно всё это.

Для начала посмотрим что за собой тянет пул, который держит сервак (вместо того чтобы каждый раз создавать отдельный тред). Напишем примитивный web api, который сохраняет в статическую переменную привязанную к потоку некий GUID, и всё это дело отдает как ответ на реквест.

C#
1
2
3
4
5
6
7
8
9
10
11
12
[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
    [ThreadStatic]
    private static Guid? val;
 
    [HttpGet]
    [Route("get")]
    public string Get() 
        => $"{Environment.CurrentManagedThreadId:D3} -- {val ??= Guid.NewGuid()}";
}
клиент, который дудосит сервак по этому url, сохраняя значения

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
using System.Collections.Concurrent;
 
await Task.Delay(TimeSpan.FromSeconds(2)); // хак, чтобы 100% успел стартануть сервак
 
await Test1();
 
Console.WriteLine("Nya");
Console.ReadKey();
 
async Task Test1()
{
    const string Url = "http://localhost:5127/test/get";
    var dic = new ConcurrentDictionary<int, ConcurrentBag<Guid>>();
 
    async Task Running()
    {
        using var client = new HttpClient();
        for (var i = 0; i < 1000; i++)
        {
            var response = await client.GetStringAsync(Url);
            var split = response.Split(" -- ");
            var id = int.Parse(split[0]);
            var guid = Guid.Parse(split[1]);
            var list = dic.GetOrAdd(id, _ => new());
            list.Add(guid);
        }
    }
 
    var tasks = new Task[50];
    for (var i = 0; i < tasks.Length; i++)
        tasks[i] = Running();
    await Task.WhenAll(tasks);
 
    var index = 0;
    foreach (var item in dic)
        Console.WriteLine($"[{index++}] {item.Key} : {string.Join("; ", item.Value.Distinct())}");
}
результат
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[0] 4 : bfba5be4-acfd-474e-b98d-7cd364390387
[1] 6 : a84415da-c764-46aa-a6f1-f905ab70936e
[2] 9 : d23c36b5-7b67-4831-a3c3-286ef8ae3fe7
[3] 10 : 959b97bb-854b-4f3e-b8b8-4f7e43e8da4d
[4] 13 : 5c79087b-62df-44f0-8f22-b756e01e0b6e
[5] 14 : b8ac4649-feee-42d2-bf3b-520c723f2aea
[6] 15 : 4e14bc57-e804-4143-97dd-836ceaf11c44
[7] 16 : 47fd6168-312f-4e22-93fa-658d37f18b84
[8] 17 : 0d813ffc-4ad9-4d49-8c74-1e63a4d1eb39
[9] 18 : b2519c73-0f34-4a26-b40c-946c36829447
[10] 19 : 2786ebe6-1712-4fe9-b649-e2245886feec
[11] 20 : f233280e-0633-454f-b0c2-427ab1d36a5c
[12] 21 : ac0eb629-818e-4781-9ae0-8b77a45b5eb7
[13] 22 : fc194294-93f5-4982-a7a1-97895f74370e
Как видим, у нас нигде не задублировалось значение, так как потоки переиспользовались. Ещё можно заметить что на 50к запросов хватило всего 14 тредов.

Теперь по перфомансу, берем "типичную" задачу: запрос, ждем 5 секунд, возвращаем некий результат. По сути типичная вычитка из БД (хотя 5с это конечно дофига). Ставим у клиента таймаут 10 сек (что вроде как двукратный запас) и пробуем запросить "одновременно" скажем 50 раз.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
    private readonly static MockDB _repository = new();
 
    [HttpGet]
    [Route("get2")]
    public string Get2()
        => _repository.ReadData();
}
 
class MockDB
{
    public string ReadData()
    {
        Thread.Sleep(TimeSpan.FromSeconds(5));
        return "Nya!";
    }
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
using System.Collections.Concurrent;
 
await Task.Delay(TimeSpan.FromSeconds(2));
 
await Test2();
 
Console.WriteLine("Nya");
Console.ReadKey();
 
async Task Test2()
{
    const string Url = "http://localhost:5127/test/get2";
 
    var completed = 0;
    var failed = 0;
 
    async Task Running()
    {
        using var client = new HttpClient()
        { 
            Timeout = TimeSpan.FromSeconds(10)
        };
        try
        {
            var result = await client.GetStringAsync(Url);
            if (result == "Nya!")
                Interlocked.Increment(ref completed);
            else
                Interlocked.Increment(ref failed);
        }
        catch
        {
            Interlocked.Increment(ref failed);
        }
    }
 
    var tasks = new Task[50];
    for (var i = 0; i < tasks.Length; i++)
        tasks[i] = Running();
    await Task.WhenAll(tasks);
 
    Console.WriteLine($"completed - {completed}");
    Console.WriteLine($"failed    - {failed}");
}
Результат
Code
1
2
completed - 15
failed    - 35
Как видим наш простецкий сервак уже не справляется. На intel i9-8950HK (6 ядер по 2.9Гц). По ходу либо проц УГ, либо код. Попробуем асинхронный подход.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
    private readonly static MockDB _repository = new();
 
    [HttpGet]
    [Route("get3")]
    public async Task<string> Get3()
        => await _repository.ReadDataAsync();
}
 
class MockDB
{
    public async Task<string> ReadDataAsync() 
    {
        await Task.Delay(TimeSpan.FromSeconds(5));
        return "Nya!";
    }
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
using System.Collections.Concurrent;
 
await Task.Delay(TimeSpan.FromSeconds(2));
 
await Test2();
 
Console.WriteLine("Nya");
Console.ReadKey();
 
async Task Test2()
{
    const string Url = "http://localhost:5127/test/get3";
 
    var completed = 0;
    var failed = 0;
 
    async Task Running()
    {
        using var client = new HttpClient()
        { 
            Timeout = TimeSpan.FromSeconds(10)
        };
        try
        {
            var result = await client.GetStringAsync(Url);
            if (result == "Nya!")
                Interlocked.Increment(ref completed);
            else
                Interlocked.Increment(ref failed);
        }
        catch
        {
            Interlocked.Increment(ref failed);
        }
    }
 
    var tasks = new Task[5000];
    for (var i = 0; i < tasks.Length; i++)
        tasks[i] = Running();
    await Task.WhenAll(tasks);
 
    Console.WriteLine($"completed - {completed}");
    Console.WriteLine($"failed    - {failed}");
}
Для начала рекомендую поиграть в игру "найди 10 отличий" (это к вопросу, насколько написание асинхронного кода труднее). Особенно на клиентской части, где поменялось количество запросов. Их стало слегка больше, всего каких-то х100.

Результат этого безобразия.
Code
1
2
completed - 5000
failed    - 0
МАГИЯ! Ради смеха попробовал 50к запрос (что на одном ПК несколько бессмысленно по куче причин) и даже тут занятная картина: 46к+ отработавших запросов.

Замечу что т.к. всё это крутилось на одном CPU, во-первых запросы шли не моментально, а на сколько успевал проц в конкуренции с серваком. Во-вторых, 50к запросов заходило не моментально, т.к. на клиентской части тоже есть пул (внезапно), который обрабатывает наши задачи, и что-то мне подсказывает что скорость добавления нового треда там сопоставим с теми же задержками, что и на серваке.

Ложка дегтя: сделаем ситуацию для асинхронного кода чуть реалистичнее: задержка на выполнение какой-то не асинхронной задачи и пнем всего 50 запросов.

C#
1
2
3
4
5
6
7
8
9
class MockDB
{
    public async Task<string> ReadDataAsync() 
    {
        Thread.Sleep(TimeSpan.FromSeconds(2));
        await Task.Delay(TimeSpan.FromSeconds(3));
        return "Nya!";
    }
}
Code
1
2
completed - 44
failed    - 6
Как видим магия резко испарилась, но всё ещё значительно бодрее чисто синхронного запроса. Более того, нужно понимать что асинхронные запросы появились для определенных ситуаций: когда работаем с БД (довольно часто на самом деле), запрашиваем внешнее api (реже, но вполне актуальная задача для многих проектов), либо банально что-то читаем с диска (тут профит от асинхронщины под вопросом). Ещё я не задевал вопрос распараллеливания задач. Но в общем случае у нас не всегда получится сделать запрос асинхронным по причине того что там нечему быть таковым. Банальный пример -- a+b. Эту задачу НИКАК НЕ СДЕЛАТЬ АСИНХРОННОЙ, что несколько избавляет нас от вопроса в принципе.

Проект на "потыкать лично" прилагается ниже
Вложения
Тип файла: zip DraftCheckAsync.zip (4.7 Кб, 2 просмотров)
1
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
05.08.2023, 15:04
Цитата Сообщение от Wolfdp Посмотреть сообщение
Появилось непреодолимое желание поговнокодить
Любите вы себе жизнь усложнять!

C#
1
2
3
4
5
6
7
8
9
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
 
var busyTime = TimeSpan.FromSeconds(0.1);
 
app.MapGet("/async", async () => await Task.Delay(busyTime));
app.MapGet("/thread", () => Thread.Sleep(busyTime));
 
app.Run();
Потом берем ApacheBench и стресс-тестим оба урла. Сервер можно перезапустить между тестами для чистоты эксперимента.
Эмулируем 50к запросов, разбитых на 10к одновременных соединений, т.е. в среднем будет где-то 5 запросов с одного соединения:
Windows Batch file
1
.\ab.exe -c 10000 -k -n 50000 "http://localhost:5028/thread"
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Concurrency Level:      10000
Time taken for tests:   131.593 seconds
Complete requests:      50000
Failed requests:        0
Keep-Alive requests:    50000
Total transferred:      5800000 bytes
HTML transferred:       0 bytes
Requests per second:    379.96 [#/sec] (mean)
Time per request:       26318.690 [ms] (mean)
Time per request:       2.632 [ms] (mean, across all concurrent requests)
Transfer rate:          43.04 [Kbytes/sec] received
 
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1  17.9      0     516
Processing:   521 21089 6897.5  23606   42501
Waiting:      174 21088 6897.9  23606   42501
Total:        521 21090 6897.2  23606   42501
 
Percentage of the requests served within a certain time (ms)
  50%  23606
  66%  23802
  75%  25024
  80%  25528
  90%  26522
  95%  29311
  98%  32599
  99%  35255
 100%  42501 (longest request)
Windows Batch file
1
.\ab.exe -c 10000 -k -n 50000 "http://localhost:5028/async"
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Concurrency Level:      10000
Time taken for tests:   11.003 seconds
Complete requests:      50000
Failed requests:        0
Keep-Alive requests:    50000
Total transferred:      5800000 bytes
HTML transferred:       0 bytes
Requests per second:    4544.24 [#/sec] (mean)
Time per request:       2200.589 [ms] (mean)
Time per request:       0.220 [ms] (mean, across all concurrent requests)
Transfer rate:          514.78 [Kbytes/sec] received
 
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.2      0       5
Processing:   445 1777 432.6   1887    2919
Waiting:      171 1776 432.6   1887    2898
Total:        445 1777 432.6   1887    2919
 
Percentage of the requests served within a certain time (ms)
  50%   1887
  66%   1974
  75%   2005
  80%   2044
  90%   2121
  95%   2282
  98%   2647
  99%   2782
 100%   2919 (longest request)
Тестировалось на домашнем лаптопе (Win 11 Home), а не на толковом сервере, потому вот такие задержки.
1
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
05.08.2023, 16:44
kolorotur, увы, с бренчмарками плохо знаком, да и не особо хотелось завязываться на тайминги, так как по хорошему это нужно отключать все лишнее для чистоты эксперимента (в идеале еще и второй ноут задействовать). Да и изначально предполагал что код придеться сильно сложнее писать (особенно на серверной части), чтобы достичь наглядных просадок, но оказалось всё намного веселей.

Тут больше вопрос к Mastodon_dev, остались ли у него вопрлсы по "зачем асинхроность". А то примеры это хорошо, но их код тоже нужно разбирать.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
05.08.2023, 16:44

Отправка запроса Get к WebApi
У меня есть Web Api Вот часть кода контроллера namespace WebApplication9.Controllers { &quot;)] public class...

Отправка запроса Get к WebApi
У меня есть Web Api Вот часть кода контроллера namespace WebApplication9.Controllers { &quot;)] public class...

Вставка картинки в WebApi
Хочу вставить картинку как массив байтов. Пробовала через MediaTypeFormatter, но результата нет. ApiContoller public...

WebApi + Html + css
Как в Web Api создавать фронтенд, допустим я хочу сделать веб приложение где нужно считывать данные с файлов и мне нужно, чтобы был хоть...

WebAPI случается timeout
Добрый день, коллеги. Прошу помочь разобраться в причине периодического появления тайм-аута в приложении Web API. В основном все...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
33
Ответ Создать тему
Новые блоги и статьи
Часы электронные
Uhbif79 12.08.2026
Выкладываю программу часов. Программа позволяет: 1. Использовать системное время и дату, 2. Есть возможность вводить время и дату вручную. 3. Реализованы 2 будильника: начало и конец рабочего дня. . . .
Часы с будильником на основе класса QLCDNumber
Uhbif79 12.08.2026
Всем добрый день, выкладываю программу часов с будильником на основе класса QLCDNumber. Здесь я пробовал самостоятельно создавал классы, впервые столкнулся с видимостью переменной одного класса из. . .
Установка MinGW GCC 16.2 и CMake
8Observer8 10.08.2026
VK Видео: https:/ / vkvideo. ru/ video-240781534_456239017 YouTube: eY5-5PyI9NM Текстовая версия
Неделя из жизни имитационной модели склада: мои кривые руки растут, откуда надо
anaschu 10.08.2026
Неделя из жизни имитационной модели склада: как я почти написал неправильную логику и что с этим делать Работаю сейчас над учебно-рабочим проектом: строю в AnyLogic имитационную модель процессов. . .
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru