【问题标题】:How do I monitor specific tasks with OmniThreadLibrary如何使用 OmniThreadLibrary 监控特定任务
【发布时间】:2015-04-03 13:20:13
【问题描述】:

我想使用 OmniThreadLibrary 的默认线程池,即不创建自己的本地线程池。

我有一个方法 ValidateInvoiceFile。发票文件只是一个独立的发票对象列表。

ValidateInvoiceFile 在我的服务中被调用。用户 1 验证文件 1,用户 2 验证文件 2 - 这将发生在 2 个完全独立的调用中

例如

用户 1 - 文件 1 - 发票 1、发票 2、发票 3

用户 2 - 文件 2 - 发票 34231、发票 31235

每张发票都将在其自己的任务中进行验证。所以在这种情况下,我将有 5 个任务。

我需要我的 ValidateInvoiceFiles 过程等到所有创建的任务都完成。不是所有的任务。在很多情况下,人们希望等到所有任务都完成后,但这里并非如此。

文件 1 的 ValidateInvoices 调用对文件 2 的任务不感兴趣,所以我不希望它等待它们

我将如何使用 Delphi 的 OmniThreadLibrary 来做到这一点

我在考虑 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;

【问题讨论】:

  • 您使用的是哪个 Delphi?如果您至少使用 Delphi 2009,那么这里有一些高级抽象会对您有所帮助。
  • 我使用的是 Delphi XE 5
  • 我是否认为在我的情况下本地线程池不是一个好主意?可以同时验证任意数量的文件。在正常情况下,我们有大约 100 个系统实例在使用中,并且无法预测用户将要做什么!他们希望能够同时验证多个文件。我认为如果我使用本地池,我最终可能会使用太多线程
  • 你不需要本地线程池。你只需要一个更好的抽象。

标签: multithreading delphi


【解决方案1】:

类似的东西应该可以工作(如果我理解正确的话):

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;

【讨论】:

  • 好的,谢谢 2 * Environment.System.Affinity.Count 比 2 * System.CPUCount 更好?
  • 这是 OmniThreadLibrary 的表达方式。较旧的 Delphis 没有提供 CPUCount,所以我编写了自己的函数。
  • 好酷。如果这被 2 个用户在 8 个内核的机器上调用,这是否意味着可能有 16 个线程正在运行,还是会是 8 个? IE。最大线程数是应用于每个调用还是应用于幕后的池?
  • 其实NumTasks的意思就是创建了那么多线程。它们都被调度到 GlobalParallelPool 池中,默认情况下运行无限数量的线程。在您的情况下,最好将 GlobalParallelPool 限制为 System.CPUCount*2 并将每个 Parallel.ForEach 保留为默认设置。我已经更新了答案。
  • 谢谢。如果我有 2 个用户验证 2 个单独的文件,这是否意味着该过程会变慢?我正试图进入一个被验证的每个文件都是独立的位置。使用 Parallels.ForEach 是有道理的,但我担心其他用户的速度会变慢。没有线程,每个文件都有自己的会话,因此处理立即开始
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多