带有Kotlin Flow,协程和NOT暂停功能的并行IO请求

时间:2020-05-20 06:34:02

标签: kotlin concurrency kotlin-coroutines spring-vault kotlin-flow

我使用Spring Boot和WebFlux运行基于Netty的Kotlin应用程序。详细信息如下:

  • Java 11;
  • 科特林1.3.61;
  • Spring Boot 2.2.5.RELEASE;
  • Spring Vault Core 2.2.2发行。

我在Web层上得到一个文件。 WebFlux用它创建一个Partorg.springframework.http.codec.multipart)。数据以大小为4Kb的Flux块流的形式存储在Part的Project Reactor的DataBuffer中:

Flux<DataBuffer> content();

由于遵守框架的一致性,我将Flux转换为Kotlin的Flow

然后,我使用同步Vault客户端的encrypt(...)flatMapMerge方法中异步提交块(据我了解)(注意encrypt(...)不是suspend,并且是HTTP客户端到远程加密提供程序的包装):

public String encrypt(String keyName, String plaintext);

我检查了这个答案https://stackoverflow.com/a/58659423/6612401,发现flow { emit(...)}应该使用基于流的方法。

我的问题是,我可以将这种基于流程的方法用于非suspend函数吗?考虑到我正在使用runBlocking(Dispatchers.IO)suspend fold(...)函数,还是有更好的方法。

代码如下:

@FlowPreview
@ExperimentalCoroutinesApi
private fun getOpenByteArrayAndEncryptText(part: Part): Pair<ByteArray, String> = runBlocking(Dispatchers.IO) {
    val pair = part.content().asFlow()
            .flatMapMerge { dataBuffer ->
                val openByteArray = dataBuffer.asInputStream().readBytes()
                val opentextBase64 = Base64Utils.encodeToString(openByteArray)
                flow { emit(Pair(openByteArray,  vaultTransitTemplate.encrypt(KEY_NAME, opentextBase64))) }
            }.fold(Pair(ByteArrayOutputStream(), StringBuilder())) { result, curPair ->
                result.first.writeBytes(curPair.first)
                result.second.append(curPair.second)
                result
            }
    Pair(pair.first.toByteArray(), pair.second.toString())
}

P.S。 fold(...)函数将打开的块收集到ByteArrayOutputStream以便稍后计算哈希,然后将加密的块收集到StringBuilder作为加密文件的结果。

P.P.S。我已经尝试过了。该方法平均在我的Core i5 8gen 4物理核心计算机上提交5-7个并行请求。它完成了工作,但没有那么快。如果不将Vault部署在本地,则每1 Mb加密大约可获得1秒的时间。我了解这取决于网络的延迟。我什至不考虑Vault侧面的加密速度,由于块的大小仅为4Kb,因此闪电般快。有什么方法可以提高并发速度吗?

P.P.P.S我尝试在concurrency = MAX_CONCURRENT_REQUESTS中玩flatMapMerge{...}。到目前为止,结果并不重要。最好保留默认值。

0 个答案:

没有答案