gpt4 book ai didi

android - 如何将顺序协程 block 排入队列

转载 作者:行者123 更新时间:2023-12-04 02:30:53 25 4
gpt4 key购买 nike

我想要做什么

我有一个应用程序使用 Room with Coroutines 在数据库中保存搜索查询。也可以添加搜索建议,然后我检索这些数据以将它们显示在列表中。我还可以“固定”其中一些建议。

我的数据结构是这样的:

@Entity(
tableName = "SEARCH_HISTORY",
indices = [Index(value = ["text"], unique = true)]
)
data class Suggestion(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "suggestion_id")
val suggestionId: Long = 0L,
val text: String,
val type: SuggestionType,
@ColumnInfo(name = "insert_date")
val insertDate: Calendar
)

enum class SuggestionType(val value: Int) {
PINNED(0), HISTORY(1), SUGGESTION(2)
}

我已将“文本”字段设为唯一,以避免针对不同状态/类型的重复建议。例如:一个固定项目和之前查询过的文本的建议。

我的 Coroutine 设置如下所示:

private val parentJob: Job = Job()

private val IO: CoroutineContext
get() = parentJob + Dispatchers.IO

private val MAIN: CoroutineContext
get() = parentJob + Dispatchers.Main

private val COMPUTATION: CoroutineContext
get() = parentJob + Dispatchers.Default

而我的 DAO 基本上是这样的:

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(obj: Suggestion): Long

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(objList: List<Suggestion>): List<Long>

我还有以下公共(public)函数可以将数据插入数据库:

fun saveQueryToDb(query: String, insertDate: Calendar) {
if (query.isBlank()) {
return
}
val suggestion = Suggestion(
text = query,
insertDate = insertDate,
type = SuggestionType.HISTORY
)
CoroutineScope(IO).launch {
suggestionDAO.insert(suggestion)
}
}

fun addPin(pin: String) {
if (pin.isBlank()) {
return
}
val suggestion = Suggestion(
text = pin,
insertDate = Calendar.getInstance(),
type = SuggestionType.PINNED
)
CoroutineScope(IO).launch {
suggestionDAO.insert(suggestion)
}
}

fun addSuggestions(suggestions: List<String>) {
addItems(suggestions, SuggestionType.SUGGESTION)
}

private fun addItems(items: List<String>, suggestionType: SuggestionType) {
if (items.isEmpty()) {
return
}

CoroutineScope(COMPUTATION).launch {
val insertDate = Calendar.getInstance()
val filteredList = items.filterNot { it.isBlank() }
val suggestionList = filteredList.map { History(text = it, insertDate = insertDate, suggestionType = suggestionType) }
withContext(IO) {
suggestionDAO.insert(suggestionList)
}
}
}

还有一些其他的方法,但让我们专注于上面的那些。

编辑: 以上所有方法都是我制作的库的一部分,它们不是 suspend 因为我不想强制特定对用户的编程类型,例如在使用 lib 时强制使用 Rx 或 Coroutines。

问题

假设我尝试使用上述 addSuggestions() 方法添加建议列表,并且我还尝试使用 addPin() 添加固定建议> 方法。固定文本也出现在建议列表中。

val list = getSuggestions() // Getting a list somewhere
addSuggestions(list)
addPin(list.first())

当我尝试这样做时,有时会先添加 pin,然后它会被列表中的建议覆盖,这让我觉得我可能一直在处理某种竞争条件。由于 addSuggestions() 方法要处理的数据较多,而且两个方法会并行运行,我相信 addPin() 方法会先完成。

现在,我的 Coroutines 知识非常有限,我想知道是否有办法将这些方法调用排入队列并确保它们按照我调用它们的完全相同的顺序执行,必须强烈保证避免覆盖数据并在以后获得时髦的结果。我怎样才能实现这种行为?

最佳答案

我会遵循 Go 语言的口号“不要通过共享内存进行通信;通过通信来共享内存”,这意味着不是维护原子变量或作业并尝试在它们之间进行同步,而是将您的操作建模为消息并使用协程actors处理它们。

sealed class Message {
data AddSuggestions(val suggestions: List<String>) : Message()
data AddPin(val pin: String) : Message()
}

在你的类里面


private val parentScope = CoroutineScope(Job())

private val actor = parentScope.actor<Message>(Dispatchers.IO) {
for (msg in channel) {
when (msg) {
is Message.AddSuggestions -> TODO("Map to the Suggestion and do suggestionDAO.insert(suggestions)")
is Message.AddPin -> TODO("Map to the Pin and do suggestionDAO.insert(pin)")
}
}
}

fun addSuggestions(suggestions: List<String>) {
actor.offer(Message.AddSuggestions(suggestions))
}

fun addPin(pin: String) {
actor.offer(Message.AddPin(pin))
}

通过使用 Actor,您将能够对消息进行排队,并且它们将按 FIFO 顺序进行处理。

关于android - 如何将顺序协程 block 排入队列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64229018/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com