我正在尝试使用Parallel Programming Library
中的新System.Threading.pas
或Delphi
。
我有大量的工作要使用TTask.Run
并行工作。以下是代码段:
var D: TDataSet;
T: ITask;
TaskList: TList<ITask>;
Q: TThreadedQueue<TData>;
begin
Q := TThreadedQueue<TData>.Create;
D := Create_Uni_Direction_DataSet;
D.Open;
TaskList := TList<ITask>.Create;
while not D.Eof do begin
Q.PushItem(GetData(D));
T := TTask.Run(
procedure begin
var A: TData;
begin
A := Q.PopItem;
Process(A);
...
end
);
D.Next;
TaskList.Add(T);
end;
TTask.WaitForAll(TaskList.ToArray);
...
TaskList.Free;
Q.Free;
end;
请注意,为简化说明,代码已经过简化。
代码将在运行时在Win32平台中返回Out of Memory
错误。
由于我试图在TaskList
中保留大量ITask引用,内存问题显而易见。
我使用TTask.Run
代替TParallel
的原因有多种原因:
TThread.Synchronize
报告状态。在TThread.Synchronize
中使用TParallel
将冻结申请。由于我想监控并确保这些任务在继续之前执行,我使用TTask.WaitForAll
检查TaskList.ToArray
中的项目。
显然,for
循环仍然有效时,应该有许多任务完成执行。不再需要这些已完成的任务进行监控,因此可以从TaskList
中删除。
但是,如果任务完成了它的工作,就不容易决定或得到通知。也许Delphi的PPL
中有方法或现成的结构可以解决我不知道的问题。请分享您的想法或解决方案。
答案 0 :(得分:2)
这似乎是TParallel.For
的完美应用:
TParallel.For(1, 50000000,
procedure(i: Int64)
begin
end);
通过这种方式,您可以让RTL同时管理多少个活动线程,并且您不必创建5000万个对象,只需要有数百万个空闲任务。
答案 1 :(得分:0)
我尝试通过对WaitForAll
批ITask
项100,000
项TThreadedQueue<TArray<ITask>>
执行type
TThreadedTasksQueue_Helper = class helper for TThreadedQueue<TArray<ITask>>
public
function WaitForAll(const aTasks: TArray<ITask>): IFuture<Integer>;
end;
function TThreadedTasksQueue_Helper.WaitForAll(const aTasks: TArray<ITask>): IFuture<Integer>;
begin
PushItem(aTasks);
Result := TTask.Future<Integer>(
function: Integer
var A: TArray<ITask>;
begin
A := PopItem;
TTask.WaitForAll(A);
Result := Length(A);
end
);
end;
来解决此问题。
首先,我为WaitForAll
定义一个辅助类:
100,000
然后,我修改了冗长的循环,以便在var i: Integer;
Q: TThreadedQueue<Integer>;
Batches: TList<IFuture<Integer>>;
Batch: IFuture<Integer>;
WaitForQ: TThreadedQueue<TArray<ITask>>;
TaskList: TList<ITask>;
begin
Q := TThreadedQueue<Integer>.Create;
WaitForQ := TThreadedQueue<TArray<ITask>>.Create;
Batches := TList<IFuture<Integer>>.Create;
TaskList := TList<ITask>.Create;
for i := 1 to 50000000 do begin
Q.PushItem(i);
TaskList.Add(
TTask.Run(
procedure
begin
Q.PopItem;
end
)
);
if i mod 100000 = 0 then begin
Batches.Add(WaitForQ.WaitForAll(TaskList.ToArray));
TaskList.Clear;
end;
end;
Batches.Add(WaitForQ.WaitForAll(TaskList.ToArray));
TaskList.Clear;
for Batch in Batches do Batch.Value;
Q.Free;
WaitForQ.Free;
TaskList.Free;
Batches.Free;
end;
批次中为ITask执行 <?= $this->Form->create($news,array('type'=>'file')) ?>
<div class="col-md-12">
<?php
echo $this->Form->input('newsImage',['type'=>'file']);
echo $this->Form->input('title',['class'=>'form-control']);
echo $this->Form->input('news');
?>
</div>
<?= $this->Form->end() ?>
:
if ($this->request->is('post')) {
$target_dir = "img/news/";
$target_file = $target_dir . basename($_FILES["newsImage"]["name"]);
$fNAME = $_FILES["newsImage"]["name"];
$TMPNAME = $_FILES['newsImage']['tmp_name'];
move_uploaded_file($_FILES["newsImage"]["tmp_name"], $target_file);
$this->request->data['News']['newsImage']=$fNAME;
$news = $this->News->patchEntity($news, $this->request->data);
if ($this->News->save($news)) {
$this->Flash->success(__('The news has been saved.'));
//return $this->redirect($this->referer());
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error(__('The news could not be saved. Please, try again.'));
}
}