0

Сабж. Помогите разобраться в этой магии.
Есть такой класс.

public class ParserV2 
{
    private static SemaphoreSlim semaphore = new SemaphoreSlim(3);
    private static  HttpClient client = new HttpClient();
private Domain domain;

static ParserV2()
{
 //Устанавливаем Заголовки
}
private async Task GetDomainAsync(){//Делаем GET запрос к апи}
private async Task CheckDomainAsync(){//Делаем проверку}
private async Task<string> UpdateBdDomainAsync(){//Делаем PUT запрос к апи}
   //Метод которым запускаем все действия которые выше    
public async Task Check(CancellationToken token) 
{
    if (!token.IsCancellationRequested)
    {

        semaphore.Wait();

    do
    {     
            await GetDomainAsync();         
    }
    while (domain == null);

    do
    {
        await CheckDomainAsync();
    }
    while (domain.CMS == null);


    while(true) 
    {
        var code = await UpdateBdDomainAsync();
        if (code =="OK") 
        {
            break;      
        }
    }
    Console.WriteLine("Поток освобожден");
    semaphore.Release();
    }
}

}

Main у меня такой

CancellationTokenSource cts = new CancellationTokenSource();
List <ParserV2> parse = new List <ParserV2> ();

for (int i = 0; i < 20; i++) { parse.Add(new ParserV2()); }

List <Task> tasksParse = new List <Task> ();

foreach(var t in parse) { tasksParse.Add(new Task(() => t.Check(cts.Token))); }

foreach (var t in tasksParse) { t.Start(); }

Проблема в том что задачи начинают выполнятся только после того как в foreach всем сделает t.Start();
Я думал что таски которые я запускаю сразу будут выполнятся но это не так.
Как мне запускать таски по мере их запуска а не все сразу?

  • Таски стартуют не сразу, не моментально. Ващ foreach сильно быстрый, потому таски не успевают стартануть до того, как он закончится. Добавьте в foreach задержку типа Thread.Sleep(10000) и увидите, что таски начинают колупаться до того, как цикл кончится. – tym32167 Apr 13 '23 at 18:45
  • С ожиданием в 10 секунд теряется весь смысл. – User12351259599491 Apr 13 '23 at 18:49
  • я не предлагаю вам это ожидание оставить - вы же хотели узнать как стартуют таски? С задержкой вы увидите, что таски стартуют не сразу. Как убедитесь - задержку удалите – tym32167 Apr 13 '23 at 18:52
  • таски которые я запускаю сразу будут выполнятся но это не так это действительно не так – tym32167 Apr 13 '23 at 18:53

1 Answers1

1

Ошибка: semaphore.Wait(); замените на await semaphore.WaitAsync(); и все заработает как надо.

Не используйте конструктор new Task, вообще никогда, используйте Task.Run, тогда таски будут стартовать сразу. tasksParse.Add(Task.Run(() => t.Check(cts.Token))); - а второй цикл со .Start() не нужен.

Хотя, это же асинхронный метод, ему вообще не нужен Task.Run. Вот так надо.

tasksParse.Add(t.Check(cts.Token));

Вот ещё интересное, поразбирайтесь: Массовые асинхронные вызовы с ограничением на количество параллельных без семафора

aepot
  • 49,560
  • 1
    Ха, а слона то я и не заметил – tym32167 Apr 13 '23 at 19:47
  • @tym32167 я тоже одного не сразу заметил, дописал – aepot Apr 13 '23 at 19:56
  • Спасибо попробую, пока уже почти переписал на на меньшее количество тасков но которые будут по кругу работать. – User12351259599491 Apr 13 '23 at 20:00
  • @User12351259599491 вы используете потоки поверх асинхронной операции, масло масляное. Зачем выделять поток под то, что потоки по своей природе не занимает? :) Незачем. И await Task.WhenAll(tasksParse) не забудьте чтобы дождаться конца работы операций. – aepot Apr 13 '23 at 20:36
  • Я делаю по наитию) И как то сложно понимаю(не понимаю) и await/async можно сказать наугад ставлю – User12351259599491 Apr 13 '23 at 20:47
  • @User12351259599491 тогда просто воспользуйтесь советами. – aepot Apr 13 '23 at 20:48
  • Что значит "вы используете потоки поверх асинхронной операции"? await/async используют же вместе с Task – User12351259599491 Apr 13 '23 at 20:52
  • @User12351259599491 new Task().Start() или Task.Run стартуют поток, при этом вы заворачиваете в поток метод, который и так сам по себе возвращает Task, то есть кладете Task внутрь Task. Это бессмысленно. Явный запуск потока через Task.Run больше подходит для синхронных длительных операций, а не для асинхронных. – aepot Apr 13 '23 at 20:55