Я работаю над проектом, который является как памятью, так и вычислительно-интенсивным. Значительная часть выполнения использует многопоточность с помощью FixedThreadPool
. Вкратце; У меня есть 1 поток для извлечения данных из нескольких удаленных мест (с использованием соединений URL) и заполнения BlockingQueue
объектами, подлежащими анализу, и n потоков, которые выбирают эти объекты и запускают анализ. изменить: см. код ниже
Теперь эта настройка работает как прелесть на моей машине Linux под управлением OpenSUSE 11.3, но коллега тестирует ее на очень похожей машине, на которой Win7 получает пользовательские уведомления о тайм-аутах при опросе очереди (см. код ниже), многие из них на самом деле. Я пытаюсь контролировать использование процессора на своей машине, и, похоже, программное обеспечение не получает больше 15% процессоров, а на моей машине использование процессора поражает крышу, как я и предполагал.
Мой вопрос в том, может ли это быть признаком "голодания" очереди? Может ли быть так, что поток производителя не получает достаточно времени процессора? Если да, то каким образом я могу дать один конкретный поток в пуле более высокий приоритет?
UPDATE: Я пытался выявить проблему, без радости... Я, однако, получил некоторые новые идеи.
-
Профилирование исполнения кода с помощью JVisualVM демонстрирует очень своеобразное поведение. Методы вызываются в коротких очередях CPU-time с несколькими секундами без какого-либо прогресса между ними. Это для меня означает, что каким-то образом ОС поражает тормоза в процессе.
-
Отключение антивируса и резервных демонов не оказывает существенного влияния на это.
-
Изменение приоритета java.exe(единственного экземпляра) через диспетчер задач (рекомендуется здесь) тоже ничего не меняет. (При этом я не мог отдать приоритет "в реальном времени" для java и должен был довольствоваться "высоким" prio)
-
Профилирование использования сети показывает хороший поток данных в и из, поэтому я предполагаю, что это не узкое место (хотя это значительная часть времени выполнения процесса, но я уже знаю и почти такой же процент, что и на моей машине Linux).
Любые идеи относительно того, как ОС Win7 может ограничивать время процессора моему проекту? если это не ОС, что может быть ограничивающим фактором? Я хотел бы еще раз подчеркнуть, что машина не запускает никаких других вычислений в одно и то же время, и практически нет нагрузки на процессор, отличный от моего программного обеспечения. Это сводит меня с ума...
EDIT: соответствующий код
public ConcurrencyService(Dataset d, QueryService qserv, Set<MyObject> s){
timeout = 3;
this.qs = qserv;
this.bq = qs.getQueue();
this.ds = d;
this.analyzedObjects = s;
this.drc = DebugRoutineContainer.getInstance();
this.started = false;
int nbrOfProcs = Runtime.getRuntime().availableProcessors();
poolSize = nbrOfProcs;
pool = (ThreadPoolExecutor) Executors.newFixedThreadPool(poolSize);
drc.setScoreLogStream(new PrintStream(qs.getScoreLogFile()));
}
public void serve() throws InterruptedException {
try {
this.ds.initDataset();
this.started = true;
pool.execute(new QueryingAction(qs));
for(;;){
MyObject p = bq.poll(timeout, TimeUnit.MINUTES);
if(p != null){
if (p.getId().equals("0"))
break;
pool.submit(new AnalysisAction(ds, p, analyzedObjects, qs.getKnownAssocs()));
}else
drc.log("Timed out while waiting for an object...");
}
} catch (Exception ex) {
ex.printStackTrace();
String exit_msg = "Unexpected error in core analysis, terminating execution!";
}finally{
drc.log("--DEBUG: Termination criteria found, shutdown initiated..");
drc.getMemoryInfo(true); // dump meminfo to log
pool.shutdown();
int mins = 2;
int nCores = poolSize;
long totalTasks = pool.getTaskCount(),
compTasks = pool.getCompletedTaskCount(),
tasksRemaining = totalTasks - compTasks,
timeout = mins * tasksRemaining / nCores;
drc.log("--DEBUG: Shutdown commenced, thread pool will terminate once all objects are processed, " +
"or will timeout in : " + timeout + " minutes... \n" + compTasks + " of " + (totalTasks -1) +
" objects have been analyzed so far, " + "mean process time is: " +
drc.getMeanProcTimeAsString() + " milliseconds.");
pool.awaitTermination(timeout, TimeUnit.MINUTES);
}
}
Класс QueryingAction
- это простой Runnable
, который вызывает метод сбора данных в назначенном QueryService
объекте, который затем заполняет BlockingQueue
. Класс AnalysisAction
делает все числовые хруст для одного экземпляра MyObject
.