Почему вторая задача ожидает завершения первой?

#c# #multithreading #task #threadpool #blockingcollection

#c# #многопоточность #задача #threadpool #blockingcollection

Вопрос:

Я пишу приложение, в котором у меня есть класс Rechnungsleser с 2 методами и некоторыми полями. Поля:

 invoices = new BlockingCollection<Invoice>(new ConcurrentQueue<Invoice>());
// Total number of invoices in the XML
invoicesToProcess = XDocument.Load(sourceFile).Root.Elements().Count();
// Number of invoices consumed
invoicesProecessed = 0;


public void ReadRechnungslauf() (below)
using (XmlReader rechnungsreader = XmlReader.Create(sourceFile))
{
    // Iterate over whole file
    while (!rechnungsreader.EOF)
    {
        if (someCondition)
        {
            XElement rechnung = XNode.ReadFrom(rechnungsreader) as XElement;
            // Some minor change
            Helper.RemoveAllNamespaces(rechnung);

            if (rechnung != null)
            {
                try
                {
                    // Decent change, takes XElement, reads and changes some Elements, return object of type Invoice
                    invoices.Add(CreateRechnung(rechnung, possibleOverlays));
                }
                catch (Exception e)
                {
                    Log(e)
                    throw;
                }

            }
        }
        else
        {
            rechnungsreader.Read();
        }
    }
}

public void ProcessRechnungslauf()
{  
    Rechnung currentRechnung;
    // Check that all invoices are processed
    while (invoicesToProcess != invoicesProecessed)
    {
         // Take next enqueued item
         currentRechnung = rechnungen.Take();
         if (currentRechnung.PrintMode.Equals("Online"))
         {
              // Very computing heavy method
              printer.PrintRechnung(currentRechnung);
         }
         invoicesProcessed  ;
     }
}
  

Я инициализирую оба метода следующим образом:

 using (Rechnungsleser reader = new Rechnungsleser()
{
   Task readingTask = Task.Factory.StartNew(() =>
   {
       reader.ReadRechnungslauf();
   });
   Task processingTask = Task.Factory.StartNew(() =>
   {
       reader.ProcessRechnungslauf();
   });
   Task.WaitAll(readingTask, processingTask);
}
  

Когда я проверяю журнал, он сначала считывает все счета и помещает их в очередь, а затем начинает их обработку. Как я могу обеспечить параллелизм? Это только потому, что ProcessRechnungslauf() тогда требуется гораздо большая производительность ReadRechnungslauf() ?
Должен ли я использовать Threads или TaskParallelLibrary ? Почему?
Насколько я понимаю, a Task берет доступное Thread из Threadpool и выполняет его. Я не понимаю, почему эти две задачи не должны работать вместе.

Комментарии:

1. Предоставленного кода недостаточно для принятия каких-либо решений. Неясно, что происходит внутри ReadRechnungslauf , каковы переменные invoicesToProcess и invoicesProecessed .

2. Добавлено больше кода, я не думаю, что это особенно описательно, поскольку на самом деле не так много того, что происходит в ReadRechnungslauf

3. Хм, похоже на простой шаблон производителя-потребителя. Но ProcessRechnungslauf() должен выполнять счета. Возьмите() вместо rechnungen. Take(), поскольку rechnungen неизвестен в соответствии с вашим примером кода. Вы пытались заменить if (currentRechnung. Режим печати){ … } с помощью какого-либо другого кода, чтобы проверить, есть ли что-то блокирующее / замедляющее работу?

4. Кроме того, попробуйте пометить два потока как продолжительные с помощью TaskCreationOptions.LongRunning .

5. Как только у вас нет никакого ведения журнала внутри, ProcessRechnungslauf я предполагаю, что это происходит где-то внутри PrintRechnung . Высока вероятность того, что задачи на самом деле запускаются параллельно, но поскольку синтаксический анализ данных является более быстрым процессом, он быстро печатает все свои сообщения в журнал, в то время как длительное выполнение PrintRechnung начинает печатать в журнал с некоторого момента, который происходит позже, чем ReadRechnungslauf завершается.