Я работаю над приложением (Matt traceroute версия для Windows http://winmtr.net/), которая создает несколько потоков в каждом потоке имеет свой собственный процесс (который выполняет команду ping). ThreadPoolExecutor
выключение всех потоков через некоторое время (например, 10 секунд)
ThreadPoolExecutor
использует блокирующую очередь (выполнение задач перед их выполнением)
int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
NUMBER_OF_CORES * 2, NUMBER_OF_CORES * 2 + 2, 10L, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>()
);
PingThread.java
private class PingThread extends Thread {
@Override
public void run() {
long pingStartedAt = System.currentTimeMillis();
// PingRequest is custom object
PingRequest request = buildPingRequest(params);
if (!isCancelled() && !Thread.currentThread().isInterrupted()) {
// PingResponse is custom object
// Note:
// executePingRequest uses PingRequest to create a command
// which than create a runtime process to execute ping command
// using string response i am creating PingResponse
PingResponse pingResponse = PingUtils.executePingRequest(request);
if (pingResponse != null) {
pingResponse.setHopLocation(hopLocation);
// publish ping response to main GUI/handler
publishProgress(pingResponse);
} else
Logger.error(
"PingThread", "PingResponse isNull for " + request.toString()
);
}
}
}
Теперь, если я создаю несколько потоков, скажем более 500 в цикле и выполняю внутренний исполнитель пула
Выполнение потоков
PingThread thread = new PingThread(params);
poolExecutor.execute(thread);
Я знаю, что LinkedBlockingQueue
выполняет задачи перед их выполнением. Каждый процесс потока занимает от 200 до 400 мс, но обычно он меньше 10 мс
Что я делаю
for (int iteration = 1; iteration <= 50/*configurable*/; iteration++) {
for (int index = 0; index < 10/*configurable*/; index++) {
PingThread thread = new PingThread(someParams);
poolExecutor.execute(thread);
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Logger.error(false, e);
}
}
50 итераций займут около 25 секунд, здесь у меня есть только до 40 ответов на пинг, считающиеся потерей из-за тайм-аута. Если я увеличиваю итерации, также увеличивается потеря (экспоненциально из-за увеличения количества потоков)
Замечание:
Я запускаю это приложение на Galaxy S6 с 8 ядрами, размер пула приложений - 16, а максимальный размер пула - 16 + 2, я знаю, что процессор работает только по одному потоку за раз, он разделяет квантовое время для параллельного обработка.
Наблюдая ThreadPoolExecutor
своевременно, я вижу много задач в очереди, после таймаута в очереди все еще много потоков из-за LinkedBlockingQueue
Если я уменьшаю ни один из потоков, он отлично работает, но если его увеличение создает проблему
Проблема:
- Ответы Ping уменьшаются, когда я использую устройства с двухъядерным процессором.
- Почему в очереди присутствует много потоков, где каждый поток принимает от 10 до 50 мс (увеличение времени потока увеличится до 300 мс или больше)?
- Это должно завершиться в заданное время, почему его нет?
- Как решить эту проблему?
- Должен ли я использовать
ConcurrentLinkedQueue
, но он использует модель Producer/consumer, как-тоThreadPoolExecutor
(я думаю, что это) тоже использует эту модель. -
LinkedBlockingQueue
выполняет задачи перед их выполнением (потоки простаивают или находятся в очереди), как это преодолеть? - Установив
Thread.MAX_PRIORITY
для последних, итерации не решают проблему (более поздний итерационный поток находится в очереди) - Уменьшение количества потоков решает проблему, почему? потому что в очереди меньше потоков в очереди?
- Есть ли способ проверить, если потоки, присутствующие в очереди, их развлекают, а затем выполнять другие, не блокируя другие потоки, но в течение заданного времени.
- Добавление дополнительного времени, такого как 5 секунд, не является решением
- Изменение
corePoolSize
как в Как заставить ThreadPoolExecutor увеличить потоки до max перед очередью? не работает в моем случае.
Во время тестирования использование памяти и процессора ограничено.
Требуется подробный ответ/справка.
Edit
Когда приложение переходит в фоновый режим, потери и загрузка процессора пользователя снижаются до 0-2%, в то время как на приложение фокуса - 4-6% использования процессора. Является ли это результатом UI и других правдоподобных вещей, я попытался удалить все ненужные коды, и я изменил PingThread
на PingTask
PingTask implements Runnable {/*....*/}
Примечание: Я создал отдельное приложение на основе Java, используя тот же код, и он отлично работает на рабочем столе, поэтому можем ли мы сказать об особой проблеме ОС Android?