У меня есть сеть Java-потоков (потоковое программирование), которые обмениваются данными через каналы с фиксированной пропускной способностью, работающие под WindowsXP. Основываясь на нашем опыте с «зелеными» потоками (не вытесняющими), мы ожидали, что потоки будут реже переключать контекст (таким образом уменьшая время ЦП), если каналы будут увеличены. Однако мы обнаружили, что увеличение размера канала никак не влияет на время выполнения. Кажется, что происходит то, что Java решает переключить потоки, даже если каналы не заполнены или пусты (т. е. даже если поток не должен приостанавливаться), что требует времени ЦП без видимого преимущества. Также изменение приоритетов потоков не имеет заметного значения.
Мой вопрос заключается в том, есть ли какой-то способ убедить Java не делать ненужных переключений контекста, но откладывать переключение до тех пор, пока действительно не потребуется переключать потоки - есть ли способ изменить логику диспетчеризации Java? Или это реакция на что-то, на что я не обратил внимание?! Или существуют другие механизмы асинхронизма, например. Фабрики потоков, Runnable(s), может быть, даже демоны (!). Ответ кажется неочевидным, так как до сих пор ни один из моих корреспондентов не дал ответа (включая совсем недавно двух профессоров CS). Или, может быть, я упускаю что-то настолько очевидное, что люди не могут себе представить, что я этого не знаю...
Я добавил здесь код отправки и получения - не очень элегантный, но, похоже, работает... ;-) Если вам интересно, я подумал, что логика goLock в "отправить" может быть причиной проблемы, но ее удаление временно ничего не изменило. Я добавил код для отправки и получения...
public synchronized Packet receive() {
if (isDrained()) {
return null;
}
while (isEmpty()) {
try {
wait();
} catch (InterruptedException e) {
close();
return null;
}
if (isDrained()) {
return null;
}
}
if (isDrained()) {
return null;
}
if (isFull()) {
notifyAll(); // notify other components waiting to send
}
Packet packet = array[receivePtr];
array[receivePtr] = null;
receivePtr = (receivePtr + 1) % array.length;
//notifyAll(); // only needed if it was full
usedSlots--;
packet.setOwner(receiver);
if (null == packet.getContent()) {
traceFuncs("Received null packet");
} else {
traceFuncs("Received: " + packet.toString());
}
return packet;
}
синхронизированная логическая отправка (последний пакет пакетов, окончательная операция OutputPort) {
sender = op.sender;
if (isClosed()) {
return false;
}
while (isFull()) {
try {
wait();
} catch (InterruptedException e) {
indicateOneSenderClosed();
return false;
}
sender = op.sender;
}
if (isClosed()) {
return false;
}
try {
receiver.goLock.lockInterruptibly();
} catch (InterruptedException ex) {
return false;
}
try {
packet.clearOwner();
array[sendPtr] = packet;
sendPtr = (sendPtr + 1) % array.length;
usedSlots++; // move this to here
if (receiver.getStatus() == StatusValues.DORMANT || receiver.getStatus() == StatusValues.NOT_STARTED) {
receiver.activate(); // start or wake up if necessary
} else {
notifyAll(); // notify receiver
// other components waiting to send to this connection may also get
// notified,
// but this is handled by while statement
}
sender = null;
Component.network.active = true;
} finally {
receiver.goLock.unlock();
}
return true;
}
код>
Спасибо за вопрос! Я обсуждал тот же вопрос на форуме Sun, и вот мой последний пост на этом форуме:
На данный момент мы можем предположить, что этот эффект является результатом логики планирования Windows.
Microsoft, кажется, признает, что эта область нуждается в некотором улучшении, поскольку представляет UMS. Я цитирую: «UMS рекомендуется для приложений с высокими требованиями к производительности, которым необходимо эффективно запускать множество потоков одновременно в многопроцессорных или многоядерных системах. … Доступна UMS. начиная с 64-разрядных версий Windows 7 и Windows Server 2008 R2. Эта функция недоступна в 32-разрядных версиях Windows». Будем надеяться, что в более поздних версиях Java воспользуется преимуществами UMS.
Спасибо за вашу помощь!