Saf*_*afa 0 delphi multithreading http download progress-bar
我正在开发一个多线程的下载应用程序.我有一个线程创建了许多线程,可以下载数据.在下载时我需要查看进度条的进度,所以我将最大值设置为文件的大小,并使用IdHTTPWork计算当前下载的数据,我将其添加为线程(辅助线程)的过程.当我的应用程序启动时,主线程创建其他线程下载(在循环中)并设置开始和结束的位置(idhttp.request.range),然后每个线程开始下载,如下所示:
HTTP.Request.Range := Format('%d-%d',[begin ,end]);
HTTP.Get(url,fs);
Run Code Online (Sandbox Code Playgroud)
这是secondarythread.work的过程:
procedure TSecondaryThread.IdHTTPWork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
begin
if AWorkMode = wmRead then
position:= AWorkCount;// position is a global variable
SendMessage(HWND_BROADCAST,MyMessage, 2,position);
end;
Run Code Online (Sandbox Code Playgroud)
我不知道这是不是正确的代码,但我找不到另一种解决方案.每个线程都可以使用下载数据的值来增加位置,因此位置将包含瞬时S中的全局下载,我不知道这是否属实.现在我的问题:1-进度与当前下载的数据量不对应; 相反,它增量非常缓慢.2 - 当我添加-just当我在此过程中添加-Asend消息时,它永远不会停止工作!那么问题是什么?谢谢
通过为每个工作线程提供自己的TIdHTTP对象和自己的OnWork事件处理程序,您有了正确的想法.但是您没有正确地将这些状态更新提供给主线程.
使用PostMessage()而不是SendMessage()使您不会减慢工作线程的速度.
您有多个工作线程向主线程发布状态更新,因此请勿使用全局变量来保持进度,当然也不要让工作线程直接更新该变量.每个工作线程应将其当前状态直接放在发布到主线程的消息的参数中,然后主线程可以有一个私有计数器变量,它随每次状态更新而递增.
请勿使用HWND_BROADCAST- 将消息广播到系统中的每个顶级窗口来发布状态更新!仅将消息发布到主线程,通过发布到HWND属于主线程的消息(我建议使用AllocateHWnd()它).
尝试这样的事情:
unit StatusUpdates;
uses
Windows;
interface
type
PStatus = ^TStatus;
TStatus = record
BytesDownloadedThisTime: Int64;
BytesDownloadedSoFar: Int64;
MaxBytesBeingDownloaded: Int64;
end;
var
StatusUpdateWnd: HWND = 0;
implementation
end.
Run Code Online (Sandbox Code Playgroud)
uses
..., StatusUpdates;
type
TMainForm = class(TForm)
...
private
TotalDownloaded: Int64;
...
end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
StatusUpdateWnd := AllocateHWnd(StatusWndProc);
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
if StatusUpdateWnd <> 0 then
begin
DeallocateHWnd(StatusUpdateWnd);
StatusUpdateWnd := 0;
end;
end;
procedure TMainForm.StartDownload;
begin
ProgressBar1.Position := 0;
ProgressBar1.Max := FileSizeToBeDownloaded;
TotalDownloaded := 0;
// create download threads...
end;
procedure TMainForm.StatusWndProc(var Message: TMessage);
var
Status: PStatus;
begin
if Message.Msg = MyMessage then
begin
Status := PStatus(Message.LParam);
try
if Status.BytesDownloadedThisTime > 0 then
begin
Inc(TotalDownloaded, Status.BytesDownloadedThisTime);
ProgressBar1.Position := TotalDownloaded;
end;
// use Status for other things as needed...
finally
Dispose(Status);
end;
end else
Message.Result := DefWindowProc(StatusUpdateWnd, Message.Msg, Message.WParam, Message.LParam);
end;
Run Code Online (Sandbox Code Playgroud)
uses
..., StatusUpdates;
type
TSecondaryThread = class(TThread)
private
FTotalBytes: Int64;
FMaxBytes: Int64;
procedure PostStatus(BytesThisTime: Int64);
...
end;
procedure TSecondaryThread.PostStatus(BytesThisTime: Int64);
var
Status: PStatus;
begin
New(Status);
Status.BytesDownloadedThisTime := BytesThisTime;
Status.BytesDownloadedSoFar := FTotalBytes;
Status.MaxBytesBeingDownloaded := FMaxBytes;
if not PostMessage(StatusUpdateWnd, MyMessage, 2, LPARAM(Status)) then
Dispose(Status);
end;
procedure TSecondaryThread.IdHTTPWorkBegin(ASender: TObject; AWorkMode: TWorkMode; AWorkCountMax: Int64);
begin
if AWorkMode = wmRead then
begin
FTotalBytes := 0;
FMaxBytes := AWorkCountMax;
PostStatus(0);
end;
end;
procedure TSecondaryThread.IdHTTPWork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
var
BytesThisTime: Int64;
begin
if AWorkMode = wmRead then
begin
BytesThisTime := AWorkCount - FTotalBytes;
FTotalBytes := AWorkCount;
PostStatus(BytesThisTime);
end;
end;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
417 次 |
| 最近记录: |