2015-04-03 2 views
0

Я хочу использовать пул потоков OmniThreadLibrary по умолчанию, т. Е. Не создавать собственные локальные.Как контролировать определенные задачи с помощью OmniThreadLibrary

У меня есть метод ValidateInvoiceFile. Файл счета-фактуры - это просто список объектов-фактур, которые являются автономными.

ValidateInvoiceFile вызывается в моей службе. Пользователь 1 проверяет файл 1 и пользователь 2 проверяет файл 2 - это будет происходить в 2 полностью независимых вызовов

Например

Пользователь 1 - Файл 1 - Счет 1, Счет 2, Счет 3

пользователя 2 - Файл 2 - Счет-фактура 34231, Счет-фактура 31235

Каждый счет-фактура будет подтвержден в собственной задаче. Поэтому в этом случае у меня будет 5 задач.

Мне нужна моя процедура ValidateInvoiceFiles, чтобы дождаться завершения всех заданий, если они были созданы. НЕ все задачи. Во многих случаях люди хотят дождаться завершения всех заданий, но здесь это не так.

В ValidateInvoices призывают Файл 1 не имеет никакого интереса к задачам для файла 2, поэтому я не хочу, чтобы ждать их

Как бы я сделать это с помощью OmniThreadLibrary для Delphi

Я думал о том, событие OnThreadTerminated, но я не уверен, как сделать это только заботой о задачах, добавленных во время определенного вызова.

procedure ValidateInvoiceFile(const objInvoices: TInvoices) 
begin 
    try 
    objThreadPool := CreateThreadPool('Connection pool'); 
    objThreadPool.MaxExecuting := 2 * System.CPUCount; 

    nStart := 0; 
    nEnd := 49; 

    while nStart <= objInvoices.Count - 1 do 
    begin 
     for InvoiceIndex := nStart to nEnd do 
     begin 
     if InvoiceIndex > objInvoices.Count - 1 then 
      Break; 

     objInvoice := objInvoices[InvoiceIndex]; 

     objValidationData := TValidationData.Create(FConnection, FAllInvoices, FAllInvoices[InvoiceIndex]); 
     //I fill objValidationData with information to be given to the task 

     CreateTask(
      procedure(const task: IOmniTask) 
      var 
      objLocalInvoice: TInvoice; 
      ValidatorIndex: Integer; 
      objValidator: TInvValidator; 
      objUtilities: TUtilities; 
      objValidationData: TValidationData; 
      nLocalInvoiceIndex: Integer; 
      nValidatorIndex: Integer; 
      begin 
      nLocalInvoiceIndex := Task.Param['InvoiceIndex'].AsInteger; 
      objValidationData := TValidationData(Task.Param['objValidationData'].AsObject); 
      try 
       //Do my work here 
      finally 
       FreeAndNil(objValidationData); 
      end; 
      end 
     ) 
      .SetParameter('InvoiceIndex', InvoiceIndex) 
      .SetParameter('objValidationData', TObject(objValidationData)) 
      .Unobserved 
      .Schedule(objThreadPool); 
     end; 

     /**** This is the part I dont know how to change*****/ 
     while objThreadPool.CountExecuting + objThreadPool.CountQueued > 0 do 
     Self := Self; 

     Inc(nStart, 50); 
     Inc(nEnd, 50); 
    end; 
    finally 
    objThreadPool := nil; 
    end; 
end; 
+0

Какой Delphi вы используете? Есть абстракции высокого уровня, которые помогут вам здесь, если вы используете, по крайней мере, Delphi 2009. – gabr

+0

Я использую Delphi XE 5 – Paul

+0

Я правильно понимаю, что пулы локальных потоков в моей ситуации - это не очень хорошая идея? Одновременно может быть проверено любое количество файлов. В обычный день мы имеем около 100 экземпляров используемой системы и не можем предсказать, что сделают пользователи! Они хотят иметь возможность одновременно проверять несколько файлов. Я думаю, что если я использую локальные пулы, я мог бы использовать слишком много потоков в использовании. – Paul

ответ

2

Нечто похожее на это должно работать (если я правильно понял проблему правильно):

uses 
    OtlCommon, 
    OtlParallel; 

GlobalParallelPool.MaxExecuting := Environment.System.Affinity.Count * 2; 

procedure ValidateInvoiceFile(const objInvoices: TInvoices); 
begin 
    Parallel.ForEach(0, objInvoices.Count - 1) 
    .Execute(
     procedure(const invoiceIndex: integer) 
     begin 
     //validate objInvoices[invoiceIndex] 
     end); 
end; 
+0

ok thanks is 2 * Environment.System.Affinity.Count лучше, чем делать 2 * System.CPUCount? – Paul

+0

Это способ OmniThreadLibrary сказать то же самое. Старые Delphis не предоставили CPUCount, поэтому я написал свои собственные функции. – gabr

+0

ОК классный. Если это вызвано двумя пользователями на машине с 8 ядрами, значит ли это, что может быть 16 потоков, или 8? То есть применяются ли максимальные потоки к каждому вызову или к пулу за кулисами? – Paul

Смежные вопросы