簡體   English   中英

如何在阻塞事件中使用 kotlin 協程“即發即棄”?

[英]How to "fire and forget" with kotlin coroutines in a blocking event?

我正在制作類似於我的世界插件的東西,但是API都在Java中。

在某些時候,有事件。 每個事件都按順序觸發,API 將等待事件完成,然后再為下一個事件調用事件偵聽器。 這些事件是從主線程調用的,這意味着當您的事件偵聽器代碼正在運行時沒有其他任何東西正在運行,如果您阻塞主線程太久,應用程序最終會崩潰。

基本上,我希望當玩家打開庫存時,直接發送一些第一內容,並從數據庫中檢索一些第二內容。 在 Java 中,你會做這樣的事情:

private static final List<Item> firstContent = ...;

public static void onInventoryOpenEvent(Inventory inventory) {
    inventory.addItems(firstContent);
    forkJoinPool.submit(() -> { // "fire and forget"
        List<Item> secondContent = retrieveContentFromDB(); // long and blocking
        inventory.addItems(secondContent);
    });
}

在 kotlin 中,有些人會說要使用GlobalScope ,有些人會說不要使用它,但現在我看不到除了像這樣使用它之外的任何其他方式:

fun onInventoryOpenEvent(inventory: Inventory) { // not a suspending function
    inventory.addItems(firstContent)
    GlobalScope.launch {
        val secondContent = retrieveContentFromDB() // long and blocking
        inventory.addItems(secondContent)
    }
}

如果你真的想開火就不管了,這樣協程在任何情況下都不會被取消,GlobalScope 是正確的方法。 在實踐中,真正需要一勞永逸的情況很少見,如果您使用它,Kotlin 會給您一個關於“脆弱的 API”的警告,我想是因為有很多新手都在使用它。 這在 Android(主要使用 Kotlin)上尤其是一個問題,即使在屏幕外也應該運行的長時間運行的任務應該在服務而不是協程中處理。

但是,參考您的示例,如果inventory可能會過時並且您想在某個時候將其釋放給 GC,您應該使用自己創建的存儲在屬性中的 CoroutineScope,這樣您就可以取消它以清除任何運行協程並防止它們掛在應該為 GC 釋放的引用上。 如果 scope 可能被用於多個協程,那么你應該給它一個SupervisorJob()

private val coroutineScope = CoroutineScope(SupervisorJob())

fun onEndOfLifecycle() { // some function called when cleaning up memory 
    coroutineScope.cancel()
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM