如何防止应用程序在长时间运行过程中冻结?

时间:2016-12-12 17:16:30

标签: delphi

当我们尝试一次传递大量导入的文件时,应用程序似乎有时会冻结,这对每个文件执行以下函数的每次调用,因此建议的解决方案是添加睡眠,但我不能似乎找到了适当的文档或解释如何处理它,或者我是否可以将它作为函数中的参数传递。

这是对proc

的调用
OpenQuery(FOrderToImportQuery.Database,FOrderToImportQuery);

我建议如果我可以通过Sleep作为Param

OpenQuery(FOrderToImportQuery.Database,FOrderToImportQuery, Sleep(200));

这是函数本身减去睡眠

procedure OpenQuery(aDatabase : TIBDatabase; aQuery : TIBQuery);
begin
  if aDatabase.Connected = false  then
    databaseConnect(aDatabase);

  if aDatabase.connected then
  begin
    try
      aQuery.Open;
    except
      //try
        aDatabase.ForceClose;
        aDatabase.Open;
        aQuery.Open;
      {
      except
        on e: exception do
        begin
          Log('Error opening query : '+e.Message);
        end;
      end;
      }
    end;
  end;

end;

我的想法是希望呼叫等待,以便在再次呼叫之前可以正常完成。将Sleep放在函数本身的末尾是否合适?(在最后一个END之前)

或者将它作为参数传递给函数调用最好?如果是这样,这是如何实现的......我找不到关于这种特殊情况的任何文档。

2 个答案:

答案 0 :(得分:3)

  

我的想法是希望呼叫等待,以便在再次呼叫之前可以正常完成。

然后使用Sleep()的想法完全被误解了。

如果在单个线程中,您调用过程A,B和C,如

A;
B;
C;

然后线程中的执行只会在<{1}} 之后继续B 之后才会继续执行A 。在其中任何一个中或在它们之间添加Sleep()只会延迟一些事情:如果有一个&#34; log-jam&#34;在A中,在其中或之后添加对Sleep()的调用将毫无差别。 ABC都会调用您的OpenQuery这一事实也没有任何区别。

即使A运行异步查询也是如此,因为对异步查询的调用的全部要点是调用在查询完成之前返回 - 异步查询产生自己的后台线程,其中查询实际执行,然后通常通过调用Synchronize()将结果传递回VCL线程。

您有评论建议您将查询放在单独的工作线程中(与VCL线程分开)。在等待查询完成时停止查看VCL线程是可以的,但在工作线程中包含对Sleep()的调用也不会有帮助。

因此,您的q的真实答案是您调查并解决为什么单次调用OpenQuery导致程序挂起的原因。但那不是你所问的......

答案 1 :(得分:1)

首先,让我说我假设您的代码尽可能优化,完成所需的时间本来就很长。如果您认为情况可能并非如此,那么您应该打开一个包含查询详情的新问题,以便我们为您提供帮助。

睡觉主线绝对不是答案

Sleep函数实际上将挂起主线程达到指定的毫秒数。所以,你实际上只是比现在更加冻结你的gui。

工作线程

创建一个工作线程来处理长时间运行的工作可能是让你的程序在执行所有肮脏工作时保持响应的最佳选择。

但是,您必须采取一些预防措施,因为您可能不希望用户在运行工作线程时使用该程序。例如,您不希望用户再次单击开始按钮;或者关闭应用程序等。但是,如果这些预防措施类似于冻结主线程,那么最好还是使用长时间运行的工作来冻结它。

如果这是一个可以在中间中断的进程(正确控制数据库事务可以安全地提供此选项),也许你会想要一个取消按钮。

您的工作线程可能是这样的:

type
  TWorkerThread = class(TThread)
  private
    { Private declarations }
    FDatabase: TIBDatabase;
    FListQueries: TStringList;
  protected
    procedure Execute; override;
  public
    constructor Create(aDatabase: TIBDatabase; ListQueries: TStringList; CreateSuspended: Boolean);
    destructor Destroy; override;
  end;

implementation

{ TWorkerThread }

constructor TWorkerThread.Create(aDatabase: TIBDatabase; ListQueries: TStringList; CreateSuspended: Boolean);
begin
  FListQueries.Create;
  FListQueries.Assign(ListQueries);
  FDatabase := aDatabase;

  inherited Create(CreateSuspended);
end;

destructor TWorkerThread.Destroy;
begin
  FListQueries.Free;
  inherited;
end;

procedure TWorkerThread.Execute;
var i: Integer;
  ibQuery: TIBQuery;
begin
  { Place thread code here }
  ibQuery := TIBQuery.Create(aDatabase);
  try
    for i := 0 to FListQueries.Count - 1 do begin
      if Terminated then
        Exit;

      ibQuery.SQL.Clear;
      ibQuery.SQL.Add(FListQueries[i]);

      OpenQuery(FDatabase, ibQuery);
    end;
  finally
    ibQuery.Free;
  end;
end;

PS:对不起,如果有编译错误或TIBDatabase / TIBQuery的代码错误,我不会使用其中任何一个。

PPS:这段代码可能存在问题:我认为TIBConnection很可能不是线程安全的(我相信客户端库本身不是)。所以你实际上应该创建一个只在工作线程中使用的连接,而不是仅仅使用主线程中的相同连接。不过,我会为你留下这个更正。 ;)