WindowsXPで実行されている固定容量チャネルを介して通信するJavaスレッド(フローベースプログラミング)のネットワークがあります。「グリーン」スレッド(プリエンプティブではない)の経験に基づいて私たちが期待したのは、チャネルが大きくなった場合、スレッドがコンテキストを切り替える頻度が少なくなる(したがってCPU時間が短縮される)ということです。ただし、チャネルサイズを増やしても、実行時間に違いはないことがわかりました。起こっているように見えるのは、チャネルがいっぱいまたは空ではない場合でも(つまり、スレッドを一時停止する必要がない場合でも)Javaがスレッドを切り替えることを決定することです。これは、明らかな利点がないためにCPU時間を消費します。また、スレッドの優先順位を変更しても、目に見える違いはありません。
私の質問は、不要なコンテキストスイッチを作成しないようにJavaを説得する方法があるかどうかですが、スレッドを切り替えることが本当に必要になるまで切り替えを延期します-Javaのディスパッチングロジックを変更する方法はありますか?それとも、私が注意を払っていなかった何かに反応しているのでしょうか?!または、他の非同期メカニズム、たとえばスレッドファクトリ、Runnable(s)、デーモン(!)もあります。これまでのところ、私の特派員の誰も答えを思い付いていないので、答えは自明ではないようです(最近の2人の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;
}
synchronized boolean send(final Packet packet, final OutputPort op) {
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ビットバージョンのWindows7およびWindowsServer2008 R2以降。この機能は、32ビットバージョンのWindowsでは使用できません。」うまくいけば、Javaはいくつかの後のリリースでUMSを利用するでしょう。
ご協力いただきありがとうございます!