2016-12-06 7 views
-1

У меня есть кусок кода, как это:Как многопоточность поможет повысить производительность в этой ситуации?

while(){ 

    x = jdbc_readOperation(); 

    y = getTokens(x); 

    jdbc_insertOperation(y); 
} 

public List<String> getTokens(String divText){ 
    List<String> tokenList = new ArrayList<String>(); 
    Matcher subMatcher = Pattern.compile("\\[[^\\]]*]").matcher(divText); 
    while (subMatcher.find()) { 
     String token = subMatcher.group(); 
     tokenList.add(token); 
    } 
    return tokenList; 
} 

То, что я знаю, использую многопоточность может сэкономить время, когда один поток блокирован от ввода/вывода или сети. В этих синхронных операциях каждый шаг должен дождаться завершения своего предыдущего шага. Я хочу здесь максимизировать использование процессора на getTokens().

Моя первая мысль - положить getTokens() в методе запуска класса и создать несколько потоков. Но я думаю, что это не сработает, так как кажется, что он не может получить выгоду от производительности, имея несколько потоков в чистых вычислениях.

Является ли принятие многопоточности для повышения производительности в этом случае? Если да, то как я могу это сделать?

+1

Можем ли мы спросить, может ли выполняться «материал», выполняемый 'some_stuff()' параллельно? Или, было бы только иметь смысл, чтобы один поток делал это? –

+0

Нет общего способа сделать это. Это зависит от того, что именно делает 'some_stuff()' и как именно этот код используется в программе в целом. –

+0

Извините за неоднозначность, some_stuff() - это функция строковой обработки с единственным параметром, полученным из результата операции чтения. Я обновил выше. Но я не уверен, что это можно сделать «параллельно» в этом случае, не могли бы вы рассказать об этом? Благодарю. – zonyang

ответ

2

Это будет зависеть от темпа, который jdbc_readOperation() производит обработку данных по сравнению с темпом, который обрабатывает данные getTokens (x). Зная, что это поможет вам понять, поможет ли вам многопоточность.

Вы могли бы попробовать что-то вроде этого (как раз для вас, чтобы получить идею):

int workToBeDoneQueueSize = 1000; 
int workDoneQueueSize = 1000; 
BlockingQueue<String> workToBeDone = new LinkedBlockingQueue<>(workToBeDoneQueueSize); 
BlockingQueue<String> workDone = new LinkedBlockingQueue<>(workDoneQueueSize); 

new Thread(() -> { 
    try { 
     while (true) { 
      workToBeDone.put(jdbc_readOperation()); 
     } 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
     // handle InterruptedException here 
    } 
}).start(); 

int numOfWorkerThreads = 5; // just an example 
for (int i = 0; i < numOfWorkerThreads; i++) { 
    new Thread(() -> { 
     try { 
      while (true) { 
       workDone.put(getTokens(workToBeDone.take())); 
      } 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
      // handle InterruptedException here 
     } 
    }).start(); 
} 

new Thread(() -> { 
    // you could improve this by making a batch operation 
    try { 
     while (true) { 
      jdbc_insertOperation(workDone.take()); 
     } 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
     // handle InterruptedException here 
    } 
}).start(); 

Или вы могли бы узнать, как использовать ThreadPoolExecutor. (https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadPoolExecutor.html)

+0

Спасибо, это очень помогает. Есть ли причина использовать LinkedBlockingQueue, а не ArrayBlockingQueue в этом случае? – zonyang

+0

Нет, я так не думаю, вы тоже могли бы использовать. –

0

Чтобы ускорить получение getTokens(), вы можете разделить введенный строковый divText с помощью метода String.substring(). Вы разделили его на столько подстрок, сколько вы будете запускать Threads, запускающие метод getTokens(). Затем каждый поток будет «запускаться» на определенной подстроке divText.

Создание большего количества потоков, которые могут обрабатывать процессоры, следует избегать, поскольку контекстные переключатели создают неэффективность.

https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#substring-int-int-

В качестве альтернативы можно было бы расщепление введенную строку из getTokens с помощью метода String.split http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#split%28java.lang.String%29 например, в случае, если текст состоит из слов, разделенных пробелами или другими символами. Затем конкретные части результирующего массива String могут быть переданы в разные потоки.

+0

Это не сработает. Как вы можете заранее определить, с каких точек вы должны брать подстроки? Всякий раз, когда вы берете подстроки, он может разделить строки, которые могли бы соответствовать шаблону, если бы они были сохранены так, как они есть. –

+0

Хорошая точка, расщепление немного сложно. Вам нужно будет проверить, какая максимальная длина слова в тексте может быть, и проверить, что вы не разрезаете там (до и после). Вычисление индекса для расщепления может быть выполнено путем ориентации в этой области, заданной максимальной длиной слова, путем проверки пробелов, если divText содержит слова, разделенные пробелами. –