我正在编写一个UI,它启动SwingWorker
来调用一些外部库函数,特别是来自neuroph library,以模拟神经网络。在SwingWorker
我要么生成Genome
s的群体,要么我通过遗传算法运行一些群体来找到最好的Genome
s。
工作人员生成初始人口并返回足够快,以至于在SwingWorker.process
调用SwingWorker
之前,我无法判断对SwingWorker.done
的调用是否已完成。虽然通过遗传算法运行群体会导致UI冻结直到它完成(目前不允许我进一步测试)。使用遗传算法逻辑时,不会向UI发送.process
条消息,直到完成为止。
我还注意到,库会为实例化的神经网络生成的每个LearningEvent
写入标准输出。因此,当SwingWorker
正在处理神经网络的群体时,会产生“吨”(每个网络学习和测试3行)的输出。 这是否会导致将.process
次呼叫备份回用户界面?
有没有办法迫使SwingWorker
等待其所有.process
消息都被UI发送和接收?
以下是SwingWorker
public class MLPEnvironment extends SwingWorker<Boolean, String>
{
int gensRan = 0;
boolean usingGA;
DataSet envData;
MainView mainView;
LinkedList<Genome> population;
EnvironmentParameters envParms;
public MLPEnvironment(MainView inView, EnvironmentParameters inParms, LinkedList<Genome> inPop, DataSet inData)
{
envData = inData;
mainView = inView;
envParms = inParms;
population = inPop;
usingGA = envParms.evolveAtleastOneParameter();
}
// Main logic of worker
@Override
protected Boolean doInBackground() throws Exception
{
Boolean retVal = Boolean.TRUE;
// Generate a initial population if this flag is set
if(envParms.m_bGenerateInitPop)
{
newStatus("> Generating initial population...");
generateInitialPopulation();
}
// If we are not just generating a population, but running the GA
if(!envParms.m_bOnlyGenInitPop)
{
newStatus("> Running evolution on population...");
startBigBang();
newStatus("- Number of generations ran: " + gensRan);
}
// Otherwise just push the initial population to the UI for the user to see
else
{
newStatus("> Pushing population to UI...");
newStatus("ClearTable");
for(int i = 0; i < population.size(); i++)
{
Genome curGen = population.get(i);
String layerWidths = "";
for(int j = 0; j < curGen.getLayerWidths().size(); j++)
{
layerWidths += curGen.getLayerWidths().get(j).toString();
if(j != curGen.getLayerWidths().size()-1)
layerWidths += "-";
}
newStatus("NewRow" + GenomeFitnessResults.getResultsCSV(curGen) + curGen.getTFType() + "," + curGen.getLayerWidths().size() + "," + layerWidths + ",");
}
newStatus("- Done displaying initial population");
}
newStatus("Environment worker thread finished");
return retVal;
}
// Generate the initial population
private void generateInitialPopulation()
{
newStatus(" Initial population size: " + envParms.m_iInitPopSize);
newStatus(" DataInSize: " + envData.getInputSize() + " DataOutSize: " + envData.getOutputSize());
newStatus(" Trans: " + envParms.m_bEvolveTransferFunction + " Count: " + envParms.m_bEvolveHiddenLayerCount + " Widths: " + envParms.m_bEvolveHiddenLayerWidth);
for(int i = 0; i < envParms.m_iInitPopSize; i++)
{
population.add(Genome.getGenomeFromParms(envParms));
}
newStatus("- Finished generating initial population");
}
// The start of the GA, the beininng of the networks "universe"
private void startBigBang()
{
newStatus(" Using genetic algorithm: " + usingGA);
newStatus(" Evaluating initial population...");
population = Genome.evaluate(population, envData, envParms);
newStatus(" Done evaluating initial population");
if(usingGA)
{
newStatus(" > Starting genetic algorithm...");
for(int i = 0; i < envParms.m_iNumGenerations; i++)
{
gensRan++;
newStatus(" Generation: " + gensRan);
population = Genome.select(population, envParms);
population = Genome.crossOver(population, envParms);
population = Genome.mutate(population, envParms);
population = Genome.evaluate(population, envData, envParms);
}
newStatus(" - Genetic algorithm terminated");
}
newStatus("- Done running algorithm");
}
// Clean-up and closure after main process
@Override
protected void done()
{
try
{
final Boolean retVal = get();
mainView.environmentRunComplete(retVal, population);
}
catch (InterruptedException ex)
{
// Not sure who I can tell...
System.out.println("DC: InterruptedException");
mainView.environmentRunComplete(Boolean.FALSE, null);
}
catch (ExecutionException ex)
{
// Not sure who I can tell...
System.out.println("DC: ExecutionException");
mainView.environmentRunComplete(Boolean.FALSE, null);
}
}
// These are used to write updates to the main view
private void newStatus(String arg)
{
publish(arg);
}
@Override
protected void process(List<String> list)
{
list.stream().forEach((line) -> { mainView.newStatusLine(line); });
}
}
编辑:这是另一种方式。
我理解
publish("a");
publish("b", "c");
publish("d", "e", "f");
实际上可能会导致
process("a", "b", "c", "d", "e", "f")
被召唤。进程“批处理”进入UI时是否有任何已定义的时间间隔?当我用按钮启动swing工作器时,单击UI变得没有响应,但是库打印系统输出行,然后一旦完成所有swingworker计算,我就会在UI中看到所有调用newStatus
。
所以我知道工作人员正在做一些紧张的工作,但是为什么在所有工作完成后,在完成工作所需的几秒钟内,所有人都要调用newStatus
?在执行密集型任务之前和之前,是否应该将某些发布调用发送到UI?
如果有的话,UI不应该保持响应,因为当摇摆工作者正在工作时,没有显示任何消息吗?