Как измерить производительность / скорость метода Files.copy во время процесса? - PullRequest
0 голосов
/ 28 мая 2019

У меня есть общий абстрактный метод, который получает входной поток (может быть из сетевого сокета или из файла в локальном хранилище) и сохраняет данные на диске.

Ниже небольшого фрагментафункция:

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 голосов
/ 03 июня 2019

Поскольку я не нашел ничего встроенного, самый простой способ сделать то, что запрашивается, - это «перегрузить» требуемый метод 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")
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...