在过程进行过程中,如何测量Files.copy方法的性能/速度?

时间:2019-05-28 14:12:31

标签: java performance kotlin stream

我有一个通用的抽象方法,该方法获取输入流(可以来自网络套接字,也可以来自本地存储中的文件),然后将数据保存在磁盘上。

下面是该函数的一小段:

fun saveToFile(data: InputStream, fileDestination: File) {

            val bytesWritten = Files.copy(data, fileDestination.toPath(), StandardCopyOption.REPLACE_EXISTING)
            println("$bytesWritten bytes were saved at ${fileDestination.absolutePath}")

}

在处理/方法进行过程中,是否可以测量将数据保存在磁盘上的速度/速率?例如,是否有可能调用返回速率/速度或更新保存该数据的对象的函数?

如果我自己使用InputStream / OutputStream来实现,那么我可能会遇到以下类似情况:

fun saveData(data: InputStream, fileDestination: File, measureSpeed : (Statistics) -> Unit = { }) {

        val outputStream = fileDestination.outputStream()
        val maxBufferSize = 1024
        val totalAmountData = data.available()
        var totalBytesWritten = 0
        var bytesWriteNextIteration: Int // amount of bytes that will be sent in only one write call
        val statistics = Statistics(amountSent = 0, lastWriteBytes = 0, lastWriteTime = 1)
        while (totalBytesWritten < totalAmountData) {
            bytesWriteNextIteration = totalAmountData - totalBytesWritten
            if (bytesWriteNextIteration > maxBufferSize) {
                bytesWriteNextIteration = maxBufferSize
            }
            val bytes = ByteArray(bytesWriteNextIteration)

            val nano = measureNanoTime {
                outputStream.write(bytes)
            }
            statistics.amountSent = totalBytesWritten.toLong()
            statistics.lastWriteBytes = bytesWriteNextIteration.toLong()
            statistics.lastWriteTime = nano
            measureSpeed(statistics)
            totalBytesWritten += bytesWriteNextIteration
        }

        outputStream.flush()
        outputStream.close()
    }

    data class Statistics(var amountSent: Long, var lastWriteBytes: Long, var lastWriteTime: Long)

并使用measureSpeed方法来计算复印/传输速率。

1 个答案:

答案 0 :(得分:0)

由于我没有找到任何内置的东西,因此执行要求的最简单方法是“重载”所需的Files.copy方法并调用该函数。

重载方法可能类似于以下内容:

private val BUFFER_SIZE = 8192

@Throws(IOException::class)
private fun copy(source: InputStream, sink: OutputStream, networkStatistics: NetworkStatistics, measureSpeed : (NetworkStatistics) -> Unit = { }): Long {
    var nread = 0L
    val buf = ByteArray(BUFFER_SIZE)
    var n: Int
    n = source.read(buf)
    while (n > 0) {
        val nano = measureNanoTime {
            sink.write(buf, 0, n)
            nread += n.toLong()
            n = source.read(buf)
        }
        networkStatistics.amountSent = nread
        networkStatistics.lastPacketBytes = n.toLong()
        networkStatistics.lastPacketTime = nano
        measureSpeed(networkStatistics)
    }
    return nread
}

@Throws(IOException::class)
fun copy(`in`: InputStream, target: Path, networkStatistics: NetworkStatistics, measureSpeed : (NetworkStatistics) -> Unit = { }, vararg options: CopyOption ): Long {
    // ensure not null before opening file
    Objects.requireNonNull(`in`)

    // check for REPLACE_EXISTING
    var replaceExisting = false
    for (opt in options) {
        if (opt === StandardCopyOption.REPLACE_EXISTING) {
            replaceExisting = true
        } else {
            if (opt == null) {
                throw NullPointerException("options contains 'null'")
            } else {
                throw UnsupportedOperationException(opt.toString() + " not supported")
            }
        }
    }

    // attempt to delete an existing file
    var se: SecurityException? = null
    if (replaceExisting) {
        try {
            Files.deleteIfExists(target)
        } catch (x: SecurityException) {
            se = x
        }

    }

    // attempt to create target file. If it fails with
    // FileAlreadyExistsException then it may be because the security
    // manager prevented us from deleting the file, in which case we just
    // throw the SecurityException.
    val ostream: OutputStream
    try {
        ostream = Files.newOutputStream(target, StandardOpenOption.CREATE_NEW,
                StandardOpenOption.WRITE)
    } catch (x: FileAlreadyExistsException) {
        if (se != null)
            throw se
        // someone else won the race and created the file
        throw x
    }

    // do the copy
    ostream.use { out -> return copy(`in`, out, networkStatistics, measureSpeed = { networkStatistics -> measureSpeed(networkStatistics) }) }
}

,它将被称为:

val statistics = NetworkStatistics(responseShouldBe, 0, 0, 1)
copy(inputStream, file.toPath(), statistics, { it: NetworkStatistics -> measureSpeed(it) }, StandardCopyOption.REPLACE_EXISTING)

private fun measureSpeed(stats: NetworkStatistics) {
    val a = stats.lastPacketBytes
    val b = stats.lastPacketTime
    val miliseconds = b.toDouble() / 1000
    val seconds = miliseconds / 1000
    println("$a per ($seconds seconds) or ($miliseconds milisecs) or ($b nanosecs) -- ${(a.toDouble()/(1024*1024))/seconds} MB/seconds")
}