我的目标:
让一个类有两个方法start和stop,start方法有3个参数:
- startHour,指示一天中重新开始执行算法的小时
- isImmediatly,指示第一次且仅第一次是否立即启动算法或等待下一个startHour(如果当前时间较短,则可以从同一天开始,或者如果当前时间较长,则可以从第二天开始)
- numOfJobs表示并行启动多少个作业。在start中,我必须:
- 计算开始启动作业之前的等待时间。
- 计算作业在停止和重新启动之前必须完成其工作的最大时间,这个时间是启动它们和下一个startHour之间的时间差。
- 启动我动态创建的作业的循环
- 每个作业执行相同的操作,即:
1.我给仓库打了个电话
1.我运行一个内部循环,每5秒调用一次存储库,直到时间耗尽,或者我得到的结果取决于对存储库的调用,而不管每个作业是完成了工作还是耗尽了时间,在下一个开始时间,我必须重新启动它们。start方法可以被stop方法停止,也可以通过再次调用start()重新启动
第一次实现:
import kotlinx.coroutines.*
import java.time.Duration
import java.time.LocalDateTime
import java.time.LocalTime
class JobScheduler(private val repository: Repository) {
private val supervisorJob = SupervisorJob()
private val coroutineExceptionHandler = CoroutineExceptionHandler { _, throwable ->
println("Caught exception: $throwable")
}
private var isRunning = false
private val jobList = mutableListOf<Job>()
suspend fun start(startHour: Int, isImmediately: Boolean, numOfJobs: Int) {
isRunning = true
var waitTime = if (isImmediately) Duration.ZERO else startHour.amountTimeFromNow()
while (isRunning) {
try {
// Wait the necessary time before launching the jobs
delay(waitTime.toMillis())
// Clears all previous jobs that were still running or were scheduled but not yet executed
jobList.forEach { it.cancel() }
jobList.clear()
// Calculate the maximum duration of jobs and create jobs to launch
val maxJobDuration = startHour.amountTimeFromNow().toMillis()
supervisorScope {
val newJobs = (1..numOfJobs).map {
launch(supervisorJob + coroutineExceptionHandler) {
withTimeout(maxJobDuration) {
while (true) {
// Make the call to the repository
val success: Boolean = repository.call()
// Check if the result is what you want
if (success) {
// The result has been achieved, get out of the loop
break
}
// Wait 5 seconds before making the next call
delay(Duration.ofSeconds(5).toMillis())
}
}
}
}
// Add new jobs to the list
jobList.addAll(newJobs)
}
// Wait for the next start time
waitTime = startHour.amountTimeFromNow()
} catch (e: CancellationException) {
// Gracefully handle cancellation
println("JobScheduler has been cancelled")
break
} catch (e: Exception) {
// Handle any other exceptions
println("Caught exception: $e")
}
}
}
fun stop() {
isRunning = false
supervisorJob.cancelChildren()
jobList.clear()
}
fun Int.amountTimeFromNow(): Duration {
val now = LocalDateTime.now()
val startHour = LocalDateTime.of(now.toLocalDate(), LocalTime.of(this, 0))
val nextStart = if(now >= startHour){
startHour.plusDays(1)
}else{
startHour
}
return Duration.between(now, nextStart)
}
}
- 是对的吗 *
1条答案
按热度按时间e3bfsja21#
我不想重写你的代码,但我有一些提示给你。
使用
withTimout
和measureTimeMillis
可以使代码更简洁,可读性更好。不要使用全局作用域,而是使用
MainScope()
或CoroutineScope()
。但为了结构并发性,我建议尽可能多地使用coroutineScope{}
和supervisorScope{}
。使用
coroutinExceptionHandler
处理作业中的异常,如果不希望父作业被取消,请确保使用supervisorJob
。