简体   繁体   English

Kotlin Worker Pool - 长时间运行的 Kotlin 协程和 Java 堆 OutOfMemory

[英]Kotlin Worker Pool - Long Running Kotlin Coroutine and Java Heap OutOfMemory

I'm trying to replicate a Worker Pool in Kotlin: https://gobyexample.com/worker-pools我正在尝试在 Kotlin 中复制一个工作池: https ://gobyexample.com/worker-pools

It works wonderful, but my problem is that I get OutOfMemoryError because all object references from the worker coroutines are kept in the heap as long as the coroutine is running.它工作得很好,但我的问题是我得到 OutOfMemoryError 因为只要协程正在运行,来自工作协程的所有对象引用都保存在堆中。 How can I avoid this problem?我怎样才能避免这个问题?

Here is my code:这是我的代码:

I create a channel in Service A and receive the data everytime a channel object is received.我在服务 A 中创建一个通道,并在每次收到通道对象时接收数据。

class ServiceA(
) {

    val channel = Channel<Pair<String,ByteArray>>(10000)

    private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)

    @PostConstruct
    fun createWorkerGroup(){
        coroutineScope.launch{
            for(x in 1..5){
                launch {
                    println("Create Worker $x")
                    while (true){
                            uploadImage(channel.receive() )
                    }
                }
            }
        }
    }
 private suspend fun uploadImage(urlAndImage: Pair<String, ByteArray>){
            val (url,image) = urlAndImage
            println("Uploading Image: $url")

    }

In my controller method I send my data to a channel:在我的控制器方法中,我将数据发送到通道:

uploadService.channel.send(Pair(url, image.bytes))

The worker pool can be automatically handled by the coroutine scope with an appropriate dispatcher.工作池可以由协程范围使用适当的调度程序自动处理。

If the image upload does blocking operations, you might want to use the IO dispatcher, like so: CoroutineScope(Dispatchers.IO.limitedParallelism(5)) .如果图像上传执行阻塞操作,您可能需要使用 IO 调度程序,如下所示: CoroutineScope(Dispatchers.IO.limitedParallelism(5)) I have omitted the SupervisorJob because you do not need it for the parent coroutine that will be created in createWorkerGroup() , but for the ones created by it.我省略了SupervisorJob ,因为您不需要它用于将在createWorkerGroup()中创建的父协程,而是用于它创建的父协程。 Don't forget to create the logic for cancelling the CoroutineScope when it is no longer needed.不要忘记创建不再需要时取消CoroutineScope的逻辑。

After that, you can launch coroutines at will with no performance overhead, in the same place you did before:之后,您可以在没有性能开销的情况下随意启动协程,就像您之前所做的那样:

@PostConstruct
fun createWorkerGroup() {
    coroutineScope.launch{
        supervisorScope {
            channel.consumeEach {
                launch {
                    uploadImage(it)
                }
            }
        }
    }
}

This is the correct approach for creating and using the worker pool, but you will need to test it in order to see if it eliminates the OutOfMemoryError .这是创建和使用工作池的正确方法,但您需要对其进行测试以查看它是否消除了OutOfMemoryError You might also want to try reducing the channel's capacity.您可能还想尝试减少通道的容量。 Good luck!祝你好运!

Thank you @Halex for the help, here is my Kotlin coroutine worker pool with proper garbage collection谢谢@Halex 的帮助,这是我的 Kotlin 协程工作池,带有适当的垃圾收集

private val coroutineScope = CoroutineScope(Dispatchers.Default)
@OptIn(ExperimentalCoroutinesApi::class)
private val superVisorScope = CoroutineScope(SupervisorJob() + Dispatchers.IO.limitedParallelism(5))
@PostConstruct
fun createWorkerGroup() {
    coroutineScope.launch {
        superVisorScope.launch {
            channel.consumeEach {
                launch {
                    uploadImage(it)
                }
            }
        }
    }
    coroutineScope.cancel()
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM