【问题标题】:How to excecute code in parallel with Indy.Post如何与 Indy.Post 并行执行代码
【发布时间】:2016-07-17 02:59:45
【问题描述】:

我想将 Post 发送到速度较慢的服务器。服务器将在 20 分钟(或更长时间)内不响应,整个应用程序冻结。

我想解冻 GUI,同时等待 Post 响应以处理来自先前 Post 命令的数据。

这是我发送 Post 命令的方式:

  { POST }
  procedure TJob.SendToServer; 
  begin
  ...  
  lHTTP := TIdHTTP.Create(NIL);
  TRY
    TRY
     Server.Rspns:= lHTTP.Post(ApiServer, MegaSeqFileName);        { This won't freeze the GUI anymore because now TJob.SendToServer function is called in a TPostThread thread }                                      
    EXCEPT
     on E: Exception DO                                                                                  { Catch Internet connection problems }
      begin
       Application.ProcessMessages;
       Status:= jsNotSubmited;
       ParentTask.Log.AddError(E.Message);  
       EXIT;                                                                                          
      end;
    END;
  FINALLY
    FreeAndNil(lHTTP);
  END;

这是线程代码:

TYPE
  TPostThread= class(TThread)
  public
    Job: TJob;
    procedure Execute; override;
    procedure Done;
  end;

procedure TPostThread.Done;
begin
 Job.ThreadDone:= TRUE;
end;

procedure TPostThread.Execute;
begin
 Job.SendToServer;                                           { Send job and collect results }
 Synchronize(Done);
end;

这就是我开始线程的方式

   Job.ThreadDone:= FALSE;
   Thread:= TPostThread.Create(TRUE);
   Thread.Job:= Job;                             
   Thread.FreeOnTerminate:= FALSE;              
   Thread.Start;                                 {This calls: Job.SendToServer }

   REPEAT
     DelayEx(2000);
     if Aborted then
      begin
       MesajInfo('Task aborted.');
       Thread.Terminate;
       FreeAndNil(Thread); <----freezes here!
       EXIT(FALSE);
      end;
     //todo: run other tasks here (more exactly get results from previous Posts and send them to a different web server)
   UNTIL Job.ThreadDone;
   FreeAndNil(Thread);

问题是当我设置 Aborted = True 时,线程不会退出。它冻结在 FreeAndNil(Thread)... 这是很自然的,因为我没有检查 Thread.Execute 中的 Terminated。

【问题讨论】:

  • 释放线程时,它会等待线程过程返回。它没有。您必须拨打ProcessMessages 的电话。主线程出错,工作线程更出错。你会想退后一步,在其中加入一些设计和抽象。目前,您似乎拥有大量代码,允许任何部分访问任何其他部分。这种方法不会有好处。
  • 同意你@DavidHeffernan。但我认为最大的问题是我没有处理 TPostThread.Execute 中的 Terminated 信号。但是当整个 Execute 过程只是一行代码时,我该如何处理呢?
  • 您需要能够中止Post。能做到吗?
  • @DavidHeffernan-好问题。我认为我的问题是“二合一”。一次,我的应用程序在关闭时冻结(因为上面的代码)和第二次(如何与 Post 并行运行代码)......好吧,一旦我们解决了第一个问题,它可能会解决。
  • 通常,要中止Post(),您可以使用OnWork... 事件在线程的Terminated 属性为真时引发异常。但是,这些事件仅在字节实际在任一方向传输时才被调用。如果服务器确实需要 20 多分钟来回复(为什么??),而 TIdHTTP 只是完全闲置,OnWork... 事件将不会被调用。在这种情况下,唯一的选择是 Disconnect() 来自另一个线程上下文的套接字。即便如此,也不能保证在所有平台上都能正常工作(但在 Windows 上确实如此)。

标签: delphi indy delphi-xe7


【解决方案1】:

我有这个临时解决方案,没有线程,基于@RemyLebeau 的想法:

procedure TJob.OnHTTPProgress(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
begin
 if UserAborted=true then TIdHTTP(ASender).Disconnect;
 Application.ProcessMessages;
end;

我知道 这不是 好的答案,只是一个肮脏的 hack(这就是为什么我永远不会将此答案标记为已接受),但它使我的程序正常工作,我非常需要它会在接下来的 1-2 周内起作用。它允许我做两件事:停止程序(在上传期间)并防止 GUI 冻结。

我可以稍后再回来解决这个讨厌的问题。

【讨论】:

  • 为什么叫ProcessMessages?它会减慢下载速度,并且在线程中没有任何意义。这不是一个肮脏的黑客,你应该在像“TPostThread.Stop”这样的单独过程中这样调用它。只需在 Progress 中使用“raise”即可。
  • 我调用 ProcessMessages 来解冻 GUI(如解释)。我不在线程中调用 ProcessMessages。
  • 你使用 TPostThread 吗?如果是,则在线程中调用 OnHTTPProgress 并在线程中调用 ProcessMessages。如果您在主线程中调用它,也不要使用它。使用 TIdAntiFreeze - 您的 GUI 不会冻结,您将能够断开它(不是理想的解决方案,但可以工作)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-25
相关资源
最近更新 更多