multithreading - 如何在不卡住的情况下读取 blobfield?

标签 multithreading delphi blob freeze unidac

我想从客户端(通过网络)读取 blobfield(带有 blobstream),但应用程序在获取数据时卡住。如何在不卡住并用进度条显示百分比的情况下读取 blobfield。 (我使用的是 Delphi 和 Firebird)

我正在使用独特的组件。我从以下位置找到了此代码:http://forums.devart.com/viewtopic.php?t=14629

但它无法正常工作:

const
BlockSize= $F000;
var
Blob: TBlob;
Buffer: array of byte;
p: pointer;
pos, count: integer;

  UniQuery1.SQL.Text:= 'select * from TABLE1 where FIELD_ID = 1';
  UniQuery1.Open;

  blob:= uniquery1.GetBlob('DATA');
  SetLength(buffer, blob.Size);
  ProgressBar1.Position:= 0;
  Application.ProcessMessages;

 repeat
  count:= Blob.Read(pos, blocksize, p);
  ProgressBar1.Position:= Round(pos/Blob.Size * 100);
  pos:= pos + count;
  p:= pointer(integer(p) + count);
  Application.ProcessMessages;
 until count < blocksize;

PS:我已经设置了 uniquery 的选项:

cacheblobs:= false;
streamedblobls:= true;
deferredblobread:= true;

在repeat-until循环的第一步中,Blob.Read方法读取了所有流,因此无法正常工作。

最佳答案

您应该使用线程,这是 Delphi TThread 的示例:

type
  TMyForm = class(TForm)
  private
    FPosition: Integer;
    procedure ProgressUpdate;
    procedure Execute;
  end;

procedure TMyForm.ProgressUpdate;
begin
  ProgressBar1.Position := FPosition;
end;

procedure TMyForm.Execute;
begin
  FPosition:= 0;
  ProgressUpdate;
  Thread := TThread.CreateAnonymousThread(procedure
    begin
      repeat
        // Do some long running stuff (in chunks, so we can update the position)
        FPosition := CalculatePosition;
        // Important: Synchronize will run ProgressUpdate in the main thread!
        TThread.Synchronize(nil, ProgressUpdate); 
      until SomeCondition;
    end
  );
  Thread.Start;
end;

因此,将此模式应用于您的代码后,我们得到:

type
  TMyForm = class(TForm)
  private
    FPosition: Integer;
    procedure ProgressUpdate;
    procedure Execute;
  end;

procedure TMyForm.ProgressUpdate;
begin
  ProgressBar1.Position := FPosition;
end;

procedure TMyForm.Execute;
var
  Blob: TBlob;
  Thread: TThread;
begin
  UniQuery1.SQL.Text := 'SELECT * FROM TABLE1 WHERE FIELD_ID = 1';
  UniQuery1.Open;
  Blob := UniQuery1.GetBlob('DATA');

  FPosition:= 0;
  ProgressUpdate;
  Thread := TThread.CreateAnonymousThread(
    procedure
    const
      BlockSize = $F000;
    var
      Buffer: array of Byte;
      P: Pointer;
      Pos, Count: Integer;
    begin
      SetLength(Buffer, Blob.Size);
      repeat
        Count := Blob.Read(Pos, BlockSize, P);
        FPosition := Round(Pos / Blob.Size * 100);
        Pos := Pos + Count;
        P := Pointer(Integer(P) + Count);
        // Important: Synchronize will run ProgressUpdate in the main thread!
        TThread.Synchronize(nil, ProgressUpdate); 
      until Count < BlockSize;
    end
  );
  Thread.Start;
end;

我删除了 Application.ProcessMessage 并将所有处理移至线程。

线程正在设置 FPosition 私有(private)属性,并使用 TThread.Synchronize 将 ProgressBar 位置设置为主线程中的 FPosition

如果您的 block 大小不够大,这可能仍会阻塞 UI(由于过度同步),因此请选择适当的 block 大小或添加一些更新延迟。

您必须确保匿名线程运行时主线程中不使用 UniQuery1 对象的连接,或者将连接和查询也移至该线程。

这也可能存在重入问题,但它应该让您了解如何使用线程进行后台处理。

PS:在线程中运行查询可能也是一个好主意,特别是如果它可能需要一些时间。

关于multithreading - 如何在不卡住的情况下读取 blobfield?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21180829/

相关文章:

delphi - 方法重载和默认参数,Delphi 中还有其他选项吗?

delphi - Delphi中的二叉树实现

delphi - 具有多种类型的数组?

javascript - 将文件读取为 blob 并在 javascript 中显示

java - 如何在Java中编写一个连续检查目录中是否有文件的线程

php - 线程在编程中意味着什么?

c# - 默认情况下,子窗体是否在主窗体的同一线程上运行?

java - 服务销毁后的线程

sql - Delphi加载图像保存为sql数据库中的blob

AzureStorage Blob 服务器无法对请求进行身份验证。确保授权 header 的值格式正确,包括签名