2012-03-20 5 views
0

Следующий код (показанная часть) создает объекты класса DescCalculator и вычисляет дескрипторы и возвращает их как массивы строк. Молекула и ArrayList объектов дескрипторов передаются в.Итерация по спискам с использованием нескольких потоков

private void calcDesc() 
    { 
     try 
     { 
     StatusPanel.setStatus("Calculating Molecular Descriptors Using CDK...\n"); 
     File df = new File(Settings.getCurrentDirectory() + sep + "molDesc.csv"); 
     FileWriter dfw = new FileWriter(df); 
     LoadSDF lsdf1 = new LoadSDF(Settings.getCurrentDirectory() + sep + "marvin3D.sdf"); 
     List<IAtomContainer> mols3D = lsdf1.getCompounds(); 
     DescriptorEngine engine = new DescriptorEngine(DescriptorEngine.MOLECULAR); 
     List<String> classNames = engine.getDescriptorClassNames(); 
     List<String> removeList = new ArrayList(); 
     removeList.add("org.openscience.cdk.qsar.descriptors.molecular.IPMolecularLearningDescriptor"); 
     classNames.removeAll(removeList); 
     List<IDescriptor> instances = engine.instantiateDescriptors(classNames); 
     engine.setDescriptorInstances(instances); 

     List<String> headerItems = new ArrayList<String>(); 
     headerItems.add("CID"); 
     headerItems.add("MobCSA"); 
     for (IDescriptor descriptor : instances) { 
      String[] names = descriptor.getDescriptorNames(); 
      headerItems.addAll(Arrays.asList(names)); 
     } 
     ArrayList<IMolecularDescriptor> descriptors = new ArrayList(); 

     for (Object object : instances) 
     { 
     IMolecularDescriptor descriptor = (IMolecularDescriptor) object; 
     String[] comps = descriptor.getSpecification().getSpecificationReference().split("#"); 
     descriptors.add(descriptor); 
     } 
     String headerLine = ""; 
     for (String header : headerItems) { 
      headerLine = headerLine + header + ","; 
     } 

     dfw.append(headerLine+"\n"); 
     ExecutorService eservice = Executors.newFixedThreadPool(threads); 
     CompletionService <List<String>> cservice = new ExecutorCompletionService <List<String>> (eservice); 
     int k=0; 
     for (IAtomContainer mol : mols3D) 
     { 
      DescCalculator dc = new DescCalculator(mol,descriptors); 
      cservice.submit(dc); 
      k=k+1; 

     } 
     for (int j=1 ; j<=k; j++) 
     { 
      StatusPanel.setStatus("Calculating Descriptors for Molecule "+j+"/"+compounds.size()+" Using "+threads+" Processors\n"); 
      List<String> dataItems = cservice.take().get(); 
       for (int i = 0; i < dataItems.size(); i++) { 
       if (dataItems.get(i).equals("NaN")) { 
        dataItems.set(i, "NA"); 
       } 
      } 

      try { 
       String dataLine = ""; 
       for (String data : dataItems) { 
        dataLine = dataLine + data + ","; 
       } 
       dfw.append(dataLine+"\n"); 
      } catch (Exception e) { 
       System.out.println(e.toString()); 
      } 
     } 
dfw.close(); 
     } 
     catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 
    } 

Внутри класса есть цикл, который идет по списку дескрипторов следующим образом (часть показана). Этот код запускается в исключение параллельной модификации. Если я использую thread = 1 или итерацию дескриптора внутри синхронизированного блока {}, код работает нормально, но я не получаю требуемую параллелизацию. Как я перебираю список внутри класса DesCalculator?

public class DescCalculator implements Callable<List<String>>{ 

    private IAtomContainer mol = new Molecule(); 
    private ArrayList<IMolecularDescriptor> molDesc; 

    DescCalculator(IAtomContainer mol_, ArrayList<IMolecularDescriptor> molDesc_) 
    { 
     this.mol = mol_; 
     this.molDesc = molDesc_; 
    } 

    @Override 
    public List<String> call() { 
     List<String> dataItems = new ArrayList<String>(); 
     try 
     { 
      String title = (String) mol.getProperty("PUBCHEM_COMPOUND_CID"); 
      dataItems.add(title); 
      //String csa = Double.toString(mobcalCSA.get(ind)); 
      String csa = "NA"; 
      dataItems.add(csa); 
      int ndesc = 0; 
      for (IMolecularDescriptor descriptor : molDesc) { 
       descriptor.calculate(mol); 
       DescriptorValue value = descriptor.calculate(mol); 
       if (value.getException() != null) { 
        for (int i = 0; i < value.getNames().length; i++) { 
         dataItems.add("NA"); 
        } 
        continue; 
       } 

       IDescriptorResult result = value.getValue(); 
       if (result instanceof DoubleResult) { 
        dataItems.add(String.valueOf(((DoubleResult) result).doubleValue())); 
       } else if (result instanceof IntegerResult) { 
        dataItems.add(String.valueOf(((IntegerResult) result).intValue())); 
       } else if (result instanceof DoubleArrayResult) { 
        for (int i = 0; i < ((DoubleArrayResult) result).length(); i++) { 
         dataItems.add(String.valueOf(((DoubleArrayResult) result).get(i))); 
        } 
       } else if (result instanceof IntegerArrayResult) { 
        for (int i = 0; i < ((IntegerArrayResult) result).length(); i++) { 
         dataItems.add(String.valueOf(((IntegerArrayResult) result).get(i))); 
        } 
       } 

       ndesc++; 
      } 

     } 
     catch(Exception e) 
     { 
      e.printStackTrace(); 
     } 
     return dataItems; 
    } 

} 

печати Трассировка стека

java.util.ConcurrentModificationException 
    at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372) 
    at java.util.AbstractList$Itr.next(AbstractList.java:343) 
    at org.openscience.cdk.ChemObject.notifyChanged(ChemObject.java:187) 
    at org.openscience.cdk.ChemObject.setFlag(ChemObject.java:375) 
    at org.openscience.cdk.graph.PathTools.depthFirstTargetSearch(PathTools.java:168) 
    at org.openscience.cdk.graph.PathTools.depthFirstTargetSearch(PathTools.java:177) 
    at org.openscience.cdk.graph.PathTools.depthFirstTargetSearch(PathTools.java:177) 
    at org.openscience.cdk.graph.SpanningTree.getRing(SpanningTree.java:185) 
    at org.openscience.cdk.graph.SpanningTree.getCyclicFragmentsContainer(SpanningTree.java:221) 
    at org.openscience.cdk.atomtype.CDKAtomTypeMatcher.getRing(CDKAtomTypeMatcher.java:912) 
    at org.openscience.cdk.atomtype.CDKAtomTypeMatcher.perceiveNitrogens(CDKAtomTypeMatcher.java:730) 
    at org.openscience.cdk.atomtype.CDKAtomTypeMatcher.findMatchingAtomType(CDKAtomTypeMatcher.java:117) 
    at org.openscience.cdk.tools.manipulator.AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(AtomContainerManipulator.java:719) 
    at org.openscience.cdk.smiles.smarts.SMARTSQueryTool.initializeMolecule(SMARTSQueryTool.java:435) 
    at org.openscience.cdk.smiles.smarts.SMARTSQueryTool.matches(SMARTSQueryTool.java:214) 
    at org.openscience.cdk.smiles.smarts.SMARTSQueryTool.matches(SMARTSQueryTool.java:189) 
    at org.openscience.cdk.qsar.descriptors.molecular.AcidicGroupCountDescriptor.calculate(AcidicGroupCountDescriptor.java:135) 
    at edu.uconn.pharmacy.molfind.DescCalculator.call(DescCalculator.java:48) 
    at edu.uconn.pharmacy.molfind.DescCalculator.call(DescCalculator.java:25) 
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:138) 
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441) 
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:138) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) 
    at java.lang.Thread.run(Thread.java:680) 
+1

Похоже, что код является неполным. Вы изменяете коллекцию «molDesc» где угодно? – Tudor

+0

Каким образом вы меняете molDesc внутри вызова()? Нужно ли для других потоков видеть эти изменения? Самое простое решение - просто сделать копию списка в конструкторе. – Affe

+0

@ Тудор кажется так. OP может использовать 'CopyOnWriteArrayList' в качестве контейнера для' molDesc'. Но, чтобы точно сказать, нужно знать, как часто обновляется «molDesc», и если это правильно для «molDesc» для обновления при выполнении 'DescCalculator # call()'. –

ответ

1

Вы не должны получить исключение, если вы на самом деле модификацииCollection в то же время вы ходить по нему. Часто это можно сделать в 1 потоке, выполнив удаление из Collection, которое вы повторяете, например, в for.

Но в вашем случае, я думаю, вы удаляете из molDesc список, хотя я не вижу этого в примере кода, который вы указали. Если вам нужно удалить записи из списка, вам придется использовать другой механизм для удаления. Вы не можете изменить одну и ту же коллекцию в нескольких потоках, если она не является каким-то образом synchronized.

Пара другие идеи:

  • Теперь уверен, что она должна быть точно такой же список. Вы можете использовать каждый поток с копией списка.

    DescCalculator dc = 
        new DescCalculator(mol, new ArrayList<IMolecularDescriptor>(descriptors)); 
    
  • Вы можете просто передать в Collections.synchronizedList копию molDesc хотя я не уверен, что это то, что вы хотите.

    List<IMolecularDescriptor> syncedList = 
        Collections.synchronizedList(descriptors); 
    ... 
    DescCalculator dc = new DescCalculator(mol, syncedList); 
    
  • Каждый поток может содержать список элементов, которые необходимо удалить. В конце вы можете использовать Future, когда поток будет получен, чтобы получить удаленный список элементов и удалить их из списка в конце.

0

Ваше поле molDesc является общим состоянием между двумя и более потоками, которые обращаются к методу call(). Как вы заявили, единственный способ избежать CME - обернуть итерацию в блок synchronized() (который не позволит вам распараллеливать), или использовать структуру потокобезопасности, такую ​​как CopyOnWriteArrayList, о которой говорил Виктор.

+0

Я попробовал CopyOnWriteArrayList..Молод ArrayList никогда не менялся. – lochi

0

Оказалось, что проблема связана с объектами дескриптора, которые не являются потокобезопасными. Я благодарю Аффа за указание на это! Проблема с созданием их в классе DescCalculator. Я благодарю всех за их вклад!

Смежные вопросы