我有一个通过固定容量通道进行通信的Java线程(基于流程的编程)网络 - 在WindowsXP下运行。基于我们对“绿色”线程(非抢占式)的经验,我们所期望的是,如果通道变得更大,线程将更少地切换上下文(从而减少CPU时间)。但是,我们发现增加通道大小对运行时间没有任何影响。似乎正在发生的事情是Java决定切换线程,即使通道未满或空(即使线程不必挂起),这会花费CPU时间没有明显的优势。更改线程优先级也不会产生任何可观察到的差异。
我的问题是,是否有某种方法可以说服Java不要进行不必要的上下文切换,但是在切换线程之前必须暂停切换 - 是否有某种方法可以改变Java的调度逻辑?还是它对我没注意的事情做出反应?!或者是否存在其他异步机制,例如线程工厂,Runnable(s),甚至是守护进程(!)。答案似乎并不明显,因为到目前为止,我的通讯员都没有提出答案(包括最近两位CS教授)。或者也许我错过了一些非常明显的东西,人们无法想象我不知道它......
我在这里添加了发送和接收代码 - 不是很优雅,但似乎工作...... ;-)如果您想知道,我认为'send'中的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;
}
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;
感谢您的提问!我一直在Sun论坛上讨论同样的问题,这是我在该论坛上的最后一篇文章:
我们现在最好的猜测是这种效果来自Windows' 调度逻辑。
微软似乎承认这个领域需要一些改进 因为它引入了UMS - 我引用:“UMS推荐用于应用程序 具有高性能要求,需要高效运行许多 多处理器或多核系统上的线程并发。 ...... UMS是 从64位版本的Windows 7和Windows开始提供 Server 2008 R2。此功能在32位版本上不可用 Windows。“希望Java稍后会利用UMS 释放。
感谢您的帮助!
答案 0 :(得分:4)
绿色线程消失了(也许Solaris支持它但我怀疑)。此外,Java不会切换线程,操作系统会这样做。 Java所做的唯一事情就是向操作系统发出信号,即线程通过使用OS函数进行空闲/等待/阻塞。因此,如果你的程序遇到任何同步点,Thread.wait / sleep会发出信号,它不再需要cpu了。
除此之外,操作系统维护时间片并将从线程中取走cpu,即使在其他线程等待cpu时它仍然可以运行。
你能在这里发布更多代码吗?
答案 1 :(得分:1)
我有点尴尬 - 今天下午我突然想到可能是我担心的表现太简单的网络,因为我只有两个进程 es ,两个进程的 ORS 即可。所以Windows可能一直在努力保持处理器的平衡!所以我想知道如果我给了Windows很多进程会发生什么。
我建立了两个网络:
a)50生成组件,提供50个Discard组件 - 即高度并行的网络 - 总共100个线程
b)50生成组件提供1个丢弃组件 - 即高度“漏斗状”网络 - 这样就是51个线程
我连续运行6次,连接容量为10次,连续容量为100次,每次运行6次。每次运行总共生成50 * 20,000个信息包,共计1,000,000个数据包,并运行约1个分钟..
以下是4个案例的平均值: a)连接容量为10 - 59.151秒。 a)连接容量为100 - 52.008秒。
b)连接容量为10 - 76.745秒。 b)连接容量为100 - 60.667秒。
所以看起来连接容量确实有所作为!并且,看起来JavaFBP的表现相当不错...我为有点草率道歉 - 但也许这让我们都对多核机器中的多线程思考得更深了......; - )
再次道歉,感谢所有为此话题做出贡献的人!
答案 2 :(得分:0)
很抱歉,如果这是完全虚假的,但我很确定Java自Java 1.1以来不再使用绿色线程了。至少Wikipedia也是如此。
这会限制您使用优先级 - 但在大多数情况下,我无法实现可观察到的性能改进。