2

我有一个通过固定容量通道进行通信的 Java 线程网络(基于流的编程) - 在 WindowsXP 下运行。根据我们对“绿色”线程(非抢占式)的经验,我们期望的是,如果通道更大,线程切换上下文的频率会降低(从而减少 CPU 时间)。但是,我们发现增加通道大小对运行时间没有任何影响。似乎正在发生的事情是,即使通道未满或未空(即即使线程不必挂起),Java 仍决定切换线程,这会花费 CPU 时间而没有明显优势。更改线程优先级也不会产生任何明显的差异。

我的问题是是否有某种方法可以说服 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;

}

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 的调度逻辑造成的。

微软似乎承认这个领域需要一些改进,因为它正在引入 UMS - 我引用:“UMS 推荐用于需要在多处理器或多核系统上同时有效运行多个线程的高性能要求的应用程序。...... UMS 可用从 64 位版本的 Windows 7 和 Windows Server 2008 R2 开始。此功能在 32 位版本的 Windows 上不可用。希望 Java 将在以后的某个版本中利用 UMS。

谢谢你的帮助!

4

3 回答 3

4

Green threads are gone (maybe Solaris supports it still but I doubt that). Additionally Java does not switch threads, the OS does that. The only thing Java does is signalling to the OS, that a thread is idle/waits/blocks by using OS functions. So if your program hits any synchronisation points, does Thread.wait/sleep, it will signal, that it does not need the cpu anymore.

Besides that, the OS maintains time slices and will take away the cpu from a thread, even so it could still run, when other threads wait for the cpu.

Can you publish some more code here?

于 2009-11-19T01:15:32.343 回答
1

有点不好意思,今天下午突然想到,可能我担心性能的网络太简单了,因为我只有两个进程es和两个进程ors。因此,Windows 可能一直在努力保持处理器平衡!所以我想知道如果我给 Windows 很多进程会发生什么。

我设置了两个网络:

a) 50 个生成组件喂 50 个丢弃组件 - 即高度并行的网络 - 所以总共有 100 个线程

b) 50 生成组件馈送 1 Discard 组件 - 即高度“漏斗”网络 - 所以这是 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 的性能相当不错......我为有点仓促道歉 - 但也许它让我们都更深入地思考了多核机器中的多线程...... ;-)

再次道歉,并感谢所有对此主题发表意见的人!

于 2009-12-02T15:26:55.423 回答
0

抱歉,如果这完全是假的,但我很确定自 Java 1.1 以来 Java 不再使用绿色线程。至少维基百科也是这么说的。

这将限制您使用优先级 - 但在大多数情况下,我也无法实现可观察到的性能改进。

于 2009-11-19T00:27:28.733 回答