Perl TK Gui冻结

时间:2014-04-11 05:42:53

标签: multithreading perl user-interface

我有一个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>

有人可以提出比这更好的方法吗? 期待关于线程,共享内存的想法。

1 个答案:

答案 0 :(得分:1)

首先,如果GUI在大型30k更新期间冻结(并且永不解冻),那么您可能已经发现了Tk错误,因为这不应该发生。但是,如果它只是 无响应 一段时间,那么减轻延迟是有意义的。

过去,我使用Tk :: repeat()或Tk :: after()来驱动我的UI更新例程。用户界面通常不需要以高速率更新,因此每几百毫秒可以是合理的延迟。决定因素在很大程度上取决于您需要的界面响应程度。然后在作业导入步骤中:将引用附加到UI更新例程的列表,然后定期调用$ MW-> update()。更新例程不一定需要在每次调用期间处理完整列表,但您不希望处理过于落后。

我还建议使用一些可视指示器来识别更新仍在进行中。

如果ImportJobs的计算成本很高,显然可以执行多进程/多线程技巧来利用系统上的多个处理器。但这会增加一些复杂性和测试工作量。