我有一个perl tk应用程序,在我创建许多对象并使用对象中的信息更新perl tk gui显示。我需要在gui中的树中添加大量作业(比如30k)。如果我添加所有一起工作,gui冻结。
以下是代码段:
sub Importjobs
{
#================= start creation of objects=============================
my JobList $self = shift;
my $exportedJobList = shift;
# third parameter whether to clear the list
$self->clear () unless shift;
my $noOfProcsToBeAdded = shift || 3000;
my $cellCollection = Tasks::CellCollection::instance ();
my $calcActionsPathHash = $cellCollection->caPathCAHash ();
my $collectionCellNames = $cellCollection->allCellNames ();
my @importedJobs = ();
# if the given job list is empty, add import job list to it
push @{$self->_importJobList()}, @$exportedJobList;
$exportedJobList = [];
# do not import new jobs if the previous jobs are still being created
foreach my $taskGenJob(@{$self->getTaskGenJobObjs()}) {
goto FINISH if TaskGenJobState::CREATE == $taskGenJob->state();
}
# now get each job and add it into the imported jobs till the noOfJobs exceeds $noOfJobsToBeAdded
while(my $jobDescription = shift @{$self->_importJobList()}) {
my $taskInstantiation = $jobDescription->{'taskInstantiation'};
my $caPath = $taskInstantiation->{'calcActionPath'};
my $errMsgPrefix = 'Error importing ' . join ('-', $task, $command, $method, $caPath);
my @calcActionList;
if(defined $caPath) {
my $calcAction = $calcActionsPathHash->{ $caPath };
unless($calcAction) {
my $errMsg = $errMsgPrefix . ": the calcAction is not defined within the current CellCollection : " . $caPath;
$logger4Perl -> error ($errMsg);
next;
}
push @calcActionList, $calcAction;
} else {
my @mList;
if(not defined $method) {
push @mList, @{$task->getMethods(cellCollection => $cellCollection, command => $command)};
$method = join(' ', @mList);
} elsif($method eq $task_desc::default_method) {
@mList = ($task_desc::default_method);
} else {
@mList = sort (grep { $_ } split(/\s+|__/, $method));
}
foreach my $m (@mList) {
push(@calcActionList, @{$cellCollection->findCalcActions($task, $command, $m)});
}
}
foreach my $calcAction(@calcActionList) {
my TaskGenJob $job = TaskGenJob->new ();
$logger4Perl->info ("Adding $caPath");
push (@importedJobs, $job);
my $noOfProcsBeingAdded = $job->calculateNoOfJobExecObjs();
$noOfProcsToBeAdded -= $noOfProcsBeingAdded;
}
last if 1 > $noOfProcsToBeAdded;
}
#================= End creation of objects=============================
#Below function updates the GUI display
$self->addJobs (\@importedJobs);
#================= Mechanism which am using so that GUI will be active after certain time limit=============================
FINISH:
if(@{$self->_importJobList()}) {
$self->parentDlg()->parentWnd()->after(60000,
sub {
$GuiTasksAppl::mainDlg->Disable();
$self->importJobList([], 'noclear', 200);
$GuiTasksAppl::mainDlg->Enable();
});
}
}
目前我正在这样做的方法是使用$ noOfProcsToBeAdded变量添加说3000个作业并保持空闲一段时间并在一段时间后重复该过程。在此空闲过程中,有不同的过程处理GUI中的作业。 / p>
有人可以提出比这更好的方法吗? 期待关于线程,共享内存的想法。
答案 0 :(得分:1)
首先,如果GUI在大型30k更新期间冻结(并且永不解冻),那么您可能已经发现了Tk错误,因为这不应该发生。但是,如果它只是 无响应 一段时间,那么减轻延迟是有意义的。
过去,我使用Tk :: repeat()或Tk :: after()来驱动我的UI更新例程。用户界面通常不需要以高速率更新,因此每几百毫秒可以是合理的延迟。决定因素在很大程度上取决于您需要的界面响应程度。然后在作业导入步骤中:将引用附加到UI更新例程的列表,然后定期调用$ MW-> update()。更新例程不一定需要在每次调用期间处理完整列表,但您不希望处理过于落后。
我还建议使用一些可视指示器来识别更新仍在进行中。
如果ImportJobs的计算成本很高,显然可以执行多进程/多线程技巧来利用系统上的多个处理器。但这会增加一些复杂性和测试工作量。