我可以定期使用 kotlin-coroutines 运行 任务吗?
Can I use kotlin-coroutines run a task periodically?
看来我可以使用代码A来定期运行一个任务。
你知道 soundDb()
可以每 100 毫秒触发一次,就像 运行 周期性触发一样。
定期使用 kotlin-coroutines 运行 任务是个好方法吗?
代码A
fun calCurrentAsyn() {
viewModelScope.launch {
var b = 0.0
for (i in 1..5) {
b = b + soundDb()
delay(100)
}
b = b / 5.0
myInfo.value = b.toString() + " OK Asyn " + a++.toString()
}
}
suspend fun soundDb(): Double {
var k=0.0
for (i in 1..500000000){
k=k+i
}
return k
}
新增内容:
致乔佛里:谢谢!
1:我知道代码B是更好的风格,代码A和代码B执行的效果会一样吗?
代码B
viewModelScope.launch {
val b = computeCurrent()
myInfo.value = "$b OK Asyn ${a++}"
}
suspend fun computeCurrent(): Double {
var b = 0.0
repeat(5) {
b += soundDb()
delay(100)
}
return b / 5.0
}
suspend fun soundDb(): Double {
var k=0.0
for (i in 1..500000000){
k=k+i
}
return k
}
2:我希望从一个周期任务较长的运行ning协程中定时获取信息,如何取消流程soundDbFlow().runningAverage()
?
代码C
viewModelScope.launch {
soundDbFlow().runningAverage().collect {
println("Average = $it") // do something with it
}
}
3:你知道我可以使用Timer().scheduleAtFixedRate
在后台线程中定期获取信息,就像代码D一样,它介于Timer().scheduleAtFixedRate
和Flow
之间?
代码D
private fun startTimer() {
timer = Timer()
timer.scheduleAtFixedRate(timerTask {
recordingTime = recordingTime + 1
val temp = fromCountToTimeByInterval(recordingTime, 10)
_timeElapse.postValue(temp)
}, 0, 10)
}
private fun stopTimer() {
timer.cancel()
recordingTime = 0
_timeElapse.postValue("00:00.00")
}
重复任务的方法(launch
+ 循环)本身并不错,但问题在于您希望这个协程如何影响应用程序的其余部分。
很难判断这是为了问题而举的例子,还是你的实际代码。如果是您的实际代码,则您的用例不是经典的“周期性任务运行”:
- 它有固定的迭代次数
- 它只在执行结束时有副作用
这表明将此代码编写为挂起函数可能更有意义:
suspend fun computeCurrent(): Double {
var b = 0.0
repeat(5) {
b += soundDb()
delay(100)
}
return b / 5.0
}
然后像这样使用,更清楚结果用在什么地方:
viewModelScope.launch {
val b = computeCurrent()
myInfo.value = "$b OK Asyn ${a++}"
}
也许您实际上不需要以异步方式启动该协程(这可能取决于您如何进行其他类似调用)。
如果您需要定期(而不仅仅是在最后)从具有周期性任务的长 运行ning 协程中获取信息,您可能需要考虑构建一个 Flow
并收集它应用 side-effects:
import kotlinx.coroutines.flow.*
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
fun soundDbFlow(period: Duration = 100.milliseconds) = flow {
while (true) {
emit(soundDb())
delay(period)
}
}
fun Flow<Double>.runningAverage(): Flow<Double> = flow {
var valuesCount = 0
var sum = 0.0
collect { value ->
sum += value
valuesCount++
emit(sum / valuesCount)
}
}
然后用法可能是这样的:
viewModelScope.launch {
soundDbFlow().take(5).runningAverage().collect {
println("Average = $it") // do something with it
}
}
关于修改后的问题:
I know that Code B is the better style, will the effect of execution be same between Code A and Code B ?
代码 A 和代码 B 的行为相同。我的观点确实有一半是关于样式的,因为使它成为一个简单的挂起函数可以清楚地表明(对您和读者)它只是 returns 一个单一值。这似乎是您在新添加的 soundDb()
函数中也犯的一个错误,我不确定您是否清楚循环不是流,并且您只从这些函数返回一个值(不是多次更新任何内容)。
我的另一半观点是,因为它只是您更新的单个值,所以在 long-running 协同程序中它甚至可能不需要 运行。您可以在需要时将其与其他暂停代码集成。
how can I cancel the flow soundDbFlow().runningAverage() ?
如果取消收集协程(通过您 launch
编辑的作业或通过取消整个 viewModelScope - 当不需要组件时自动发生),流程会自动取消。如果您使用提前结束收集的终端运算符,例如 first()
、takeWhile()
、take(n).collect { .. }
等,流程也会被取消。
You know I can use Timer().scheduleAtFixedRate to get information regularly in background thread just like Code D, which is the between Timer().scheduleAtFixedRate and Flow ?
老实说,由你决定。如果您已经在使用协程,我个人更喜欢流程方法。 scheduleAtFixedRate
不会与结构化并发集成,需要手动管理取消。
看来我可以使用代码A来定期运行一个任务。
你知道 soundDb()
可以每 100 毫秒触发一次,就像 运行 周期性触发一样。
定期使用 kotlin-coroutines 运行 任务是个好方法吗?
代码A
fun calCurrentAsyn() {
viewModelScope.launch {
var b = 0.0
for (i in 1..5) {
b = b + soundDb()
delay(100)
}
b = b / 5.0
myInfo.value = b.toString() + " OK Asyn " + a++.toString()
}
}
suspend fun soundDb(): Double {
var k=0.0
for (i in 1..500000000){
k=k+i
}
return k
}
新增内容:
致乔佛里:谢谢!
1:我知道代码B是更好的风格,代码A和代码B执行的效果会一样吗?
代码B
viewModelScope.launch {
val b = computeCurrent()
myInfo.value = "$b OK Asyn ${a++}"
}
suspend fun computeCurrent(): Double {
var b = 0.0
repeat(5) {
b += soundDb()
delay(100)
}
return b / 5.0
}
suspend fun soundDb(): Double {
var k=0.0
for (i in 1..500000000){
k=k+i
}
return k
}
2:我希望从一个周期任务较长的运行ning协程中定时获取信息,如何取消流程soundDbFlow().runningAverage()
?
代码C
viewModelScope.launch {
soundDbFlow().runningAverage().collect {
println("Average = $it") // do something with it
}
}
3:你知道我可以使用Timer().scheduleAtFixedRate
在后台线程中定期获取信息,就像代码D一样,它介于Timer().scheduleAtFixedRate
和Flow
之间?
代码D
private fun startTimer() {
timer = Timer()
timer.scheduleAtFixedRate(timerTask {
recordingTime = recordingTime + 1
val temp = fromCountToTimeByInterval(recordingTime, 10)
_timeElapse.postValue(temp)
}, 0, 10)
}
private fun stopTimer() {
timer.cancel()
recordingTime = 0
_timeElapse.postValue("00:00.00")
}
重复任务的方法(launch
+ 循环)本身并不错,但问题在于您希望这个协程如何影响应用程序的其余部分。
很难判断这是为了问题而举的例子,还是你的实际代码。如果是您的实际代码,则您的用例不是经典的“周期性任务运行”:
- 它有固定的迭代次数
- 它只在执行结束时有副作用
这表明将此代码编写为挂起函数可能更有意义:
suspend fun computeCurrent(): Double {
var b = 0.0
repeat(5) {
b += soundDb()
delay(100)
}
return b / 5.0
}
然后像这样使用,更清楚结果用在什么地方:
viewModelScope.launch {
val b = computeCurrent()
myInfo.value = "$b OK Asyn ${a++}"
}
也许您实际上不需要以异步方式启动该协程(这可能取决于您如何进行其他类似调用)。
如果您需要定期(而不仅仅是在最后)从具有周期性任务的长 运行ning 协程中获取信息,您可能需要考虑构建一个 Flow
并收集它应用 side-effects:
import kotlinx.coroutines.flow.*
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
fun soundDbFlow(period: Duration = 100.milliseconds) = flow {
while (true) {
emit(soundDb())
delay(period)
}
}
fun Flow<Double>.runningAverage(): Flow<Double> = flow {
var valuesCount = 0
var sum = 0.0
collect { value ->
sum += value
valuesCount++
emit(sum / valuesCount)
}
}
然后用法可能是这样的:
viewModelScope.launch {
soundDbFlow().take(5).runningAverage().collect {
println("Average = $it") // do something with it
}
}
关于修改后的问题:
I know that Code B is the better style, will the effect of execution be same between Code A and Code B ?
代码 A 和代码 B 的行为相同。我的观点确实有一半是关于样式的,因为使它成为一个简单的挂起函数可以清楚地表明(对您和读者)它只是 returns 一个单一值。这似乎是您在新添加的 soundDb()
函数中也犯的一个错误,我不确定您是否清楚循环不是流,并且您只从这些函数返回一个值(不是多次更新任何内容)。
我的另一半观点是,因为它只是您更新的单个值,所以在 long-running 协同程序中它甚至可能不需要 运行。您可以在需要时将其与其他暂停代码集成。
how can I cancel the flow soundDbFlow().runningAverage() ?
如果取消收集协程(通过您 launch
编辑的作业或通过取消整个 viewModelScope - 当不需要组件时自动发生),流程会自动取消。如果您使用提前结束收集的终端运算符,例如 first()
、takeWhile()
、take(n).collect { .. }
等,流程也会被取消。
You know I can use Timer().scheduleAtFixedRate to get information regularly in background thread just like Code D, which is the between Timer().scheduleAtFixedRate and Flow ?
老实说,由你决定。如果您已经在使用协程,我个人更喜欢流程方法。 scheduleAtFixedRate
不会与结构化并发集成,需要手动管理取消。