以下代码似乎是我程序中最热门的地方。
JAVA_OPTS = -Xprof输出:
Compiled + native Method
5.7% 173 + 0 scala.collection.IndexedSeqOptimized$class.slice
5.1% 156 + 0 scala.collection.IndexedSeqOptimized$class.foreach
2.9% 87 + 0 java.util.regex.Pattern$BmpCharProperty.match
2.5% 76 + 0 scala.collection.IndexedSeqOptimized$class.sameElements
2.4% 73 + 0 trafacct.SubNet.contains
Slice,sameElements甚至foreach调用似乎也是最常用的。有人可以就如何优化contains()
方法提出建议吗?也许一些技术允许字节分析而不将它们转换为整数?或者没有切片的实体全序列方法?
功能SubNet.contains()将IP地址与子网匹配。
object SubNet {
def toInts(bytes: Seq[Byte]): Seq[Int] = bytes.map(_.toInt & 0xFF)
}
case class SubNet(ip:InetAddress, maskLength:Int) extends HostCategory {
import SubNet.toInts
private val bytes: Int = maskLength / 8
private val subnet = toInts(ip.getAddress)
private val bits = bytes * 8 - maskLength
def contains(host: Host) = {
if (host.ip == null && ip == null) {
true
} else if (this.ip == null) {
false
} else {
val address = toInts(host.ip.getAddress)
if (address.length != subnet.length) {
false
} else {
if (address.slice(0, bytes) != subnet.slice(0, bytes)) {
false
} else {
((address(bytes) >> (8-bits) ^ subnet(bytes) >> (8-bits)) & 0xFF) == 0
}
}
}
}
}
我明白,这种优化不会给我带来更好的吞吐量,我只是觉得我在这个简单的功能中花了这么多时间做错了。
此代码应与IPv6(16字节)兼容,我不喜欢单独处理IPv4案例的想法。
答案 0 :(得分:3)
你本身没有做错任何事;你只是使用易于使用的集合,而不是处理原语时的性能。
如果你想加快速度,你可以通过切换到使用数组和while循环获得最大的提升。我不完全清楚你写的代码甚至适用于IPv6,除了以IPv6格式存储的IPv4地址,因为你的子网可能超过256个。此外,通过测试长度,您假设没有相同地址的混合IPv6 / IPv4表示。
我忘了整个“toInts”的东西,只是存储字节数组;然后做一些事情(警告,未经测试)
def contains(host: Host): Boolean = {
//...
if (address.length != subnet.length) false
else {
var i = 0
while (i<address.length-1) {
if (address(i) != subnet(i)) return false
i += 1
}
(address(i)&0xFF) >> (8-bits) ^ (subnet(i)&0xFF) >> (8-bits) == 0
}
}
它真的不比原来的解决方案复杂,并且运行速度要快10倍。
答案 1 :(得分:1)
使用此代码,它无法正确验证。
例如:
scala> val ip = java.net.InetAddress.getByName("::ffff:1.2.176.0")
ip: java.net.InetAddress = /1.2.176.0
scala> val prefix = new InetPrefix(ip, 20)
prefix: InetPrefix = InetPrefix@6febf6f9
scala> prefix.contains(java.net.InetAddress.getByName("::ffff:1.2.176.20"))
res11: Boolean = true
scala> prefix.contains(java.net.InetAddress.getByName("::ffff:1.2.191.20"))
res12: Boolean = false
但是如果你计算那个网络:(1.2.176.0/20)
$ sipcalc 1.2.176.0/20
-[ipv4 : 1.2.176.0/20] - 0
[CIDR]
Host address - 1.2.176.0
Host address (decimal) - 16953344
Host address (hex) - 102B000
Network address - 1.2.176.0
Network mask - 255.255.240.0
Network mask (bits) - 20
Network mask (hex) - FFFFF000
Broadcast address - 1.2.191.255
Cisco wildcard - 0.0.15.255
Addresses in network - 4096
Network range - 1.2.176.0 - 1.2.191.255
Usable range - 1.2.176.1 - 1.2.191.254
-
我在Scala中重写了两个(IPv4和IPv6),并在GitHub上为每个人提供了它。它现在也在范围内验证(所以/ 20等将被视为,旧的没有。)
您可以在https://github.com/wasted/scala-util/blob/master/src/main/scala/io/wasted/util/InetPrefix.scala
找到代码(我将其分为IPv4和IPv6)我还创建了一个blogpost about this。