#Kotlin #code #coroutine
提问:为什么结果是 9 downTo 0 ?launch 的里面用了 coroutine 特性,但为什么 main 也是 suspend fun?
如果只是单线程,是怎么在最后才输出第一次的 $i 的?
suspend fun main() = coroutineScope {
for (i in 0 until 10) launch {
delay(1000L - i*10); print("$i ")
}
}
提问:为什么结果是 9 downTo 0 ?launch 的里面用了 coroutine 特性,但为什么 main 也是 suspend fun?
如果只是单线程,是怎么在最后才输出第一次的 $i 的?
Forwarded from dnaugsuz
这样也的确可以,但你的调度器必须实现抢占式调度啊,分配时间片结束得取得执行权🤔
这个就不得不依赖硬件的 timer 中断了
然后任务还要能保护现场、恢复现场,像个小协程 #coroutine 一样
要不然一个任务卡死了,调度也炸了
所以说平常还是不考虑用户级线程的情况比较好,都是谈操作系统的 Process和LWP
这个就不得不依赖硬件的 timer 中断了
然后任务还要能保护现场、恢复现场,像个小协程 #coroutine 一样
要不然一个任务卡死了,调度也炸了
所以说平常还是不考虑用户级线程的情况比较好,都是谈操作系统的 Process和LWP
今天下午在实现 Tokenizer DOM/JS 应用(基本就是包一下 Trie 树,方便咱唱有日文假名字的歌用的,这个功能苹果有,网易云音乐早就该加了哼。)
因为这个家伙设计得比较方便,可以查看字典树结构和合并后的词对应关系表(而且还能用来查单词……带自动补全草),必须设计一个字典树 string-value 遍历算法。
这个算法咱在 ParserKt 里实践过(毕竟字典树是一遍过解析关键字的重要结构),那时候写了一个纯函数(优点是没有参数所以直接 public 即可),大概就是各种 flatMap 修改合并下一层递归返回的列表啊,麻烦死了,而且性能不高
字典树这个结构也没比嵌套 Map (K-V 里 V 是 Map 的那种) 复杂多少,就是每层映射本身多对应一个『节点本身的值』而已 (比如 "stand", "standby" 里 "d" 也有存值,这种很常见的)
开始我避免了使用递归算法(虽然我最爱写递归算法了 误),想想这个遍历是嵌套 1-N 次组合,肯定要用栈,当时觉得有 keySeq, stack 这两个栈就够了(对应关系是
我开始发现现在写的算法虽然都很麻烦,但就像是思考“通项公式”一样,就是一个状态机或者操作一两个结构,明白了就很简单。
写的是每层 Trie 先给其值(如果有),然后访问它的子节点,这时候我就发现为了能递归完成这个动作,循环必须可以打断(循环的 label TypeScript 是支持的,然后要保存索引……)
我把 for in 变成
写了好多次显式栈之后,我果然还是觉得递归好,至少不需要你加 hack 。
一天半后,项目完成了,然后我突然想到了一个 #Kotlin #coroutine 必须要 executor 来执行的理由(之前一直搞不懂 runBlocking, launch 什么的是干嘛)
一个协程 yield 后要把执行权交出去,如果只是用 CPS (理解为无返回,只 callback ,但在这里收 callback 的还能恢复协程) 的话会造成调用栈不断增长,所以不能直接这样干,只能先把 Continuation 交给收它的地方,返回调度器取任务继续
关于 await/async 不知道能不能完全只用 CPS 变换来实现(反正我觉得实现起来枚举语法生成很复杂),但完整的协程是可以的。
因为这个家伙设计得比较方便,可以查看字典树结构和合并后的词对应关系表(而且还能用来查单词……带自动补全草),必须设计一个字典树 string-value 遍历算法。
这个算法咱在 ParserKt 里实践过(毕竟字典树是一遍过解析关键字的重要结构),那时候写了一个纯函数(优点是没有参数所以直接 public 即可),大概就是各种 flatMap 修改合并下一层递归返回的列表啊,麻烦死了,而且性能不高
字典树这个结构也没比嵌套 Map (K-V 里 V 是 Map 的那种) 复杂多少,就是每层映射本身多对应一个『节点本身的值』而已 (比如 "stand", "standby" 里 "d" 也有存值,这种很常见的)
开始我避免了使用递归算法(虽然我最爱写递归算法了 误),想想这个遍历是嵌套 1-N 次组合,肯定要用栈,当时觉得有 keySeq, stack 这两个栈就够了(对应关系是
stack[i] = keySeq.subSeq(0,i-1).fold(routes) { it,k -> it[k] }
,主要是缓存路径结果)我开始发现现在写的算法虽然都很麻烦,但就像是思考“通项公式”一样,就是一个状态机或者操作一两个结构,明白了就很简单。
写的是每层 Trie 先给其值(如果有),然后访问它的子节点,这时候我就发现为了能递归完成这个动作,循环必须可以打断(循环的 label TypeScript 是支持的,然后要保存索引……)
我把 for in 变成
o[Object.keys(o)[i]]
这样可以保存迭代状态(ES6 也不支持 ObjectIterator ,然后 Object.entries 在 TS 上很麻烦),写出来了(递归的话直接把 i 给 push 上去 然后 i == length 的时候就 pop),现在也感觉好不爽啊…… 索性又换成了带副作用的递归的形式。写了好多次显式栈之后,我果然还是觉得递归好,至少不需要你加 hack 。
一天半后,项目完成了,然后我突然想到了一个 #Kotlin #coroutine 必须要 executor 来执行的理由(之前一直搞不懂 runBlocking, launch 什么的是干嘛)
一个协程 yield 后要把执行权交出去,如果只是用 CPS (理解为无返回,只 callback ,但在这里收 callback 的还能恢复协程) 的话会造成调用栈不断增长,所以不能直接这样干,只能先把 Continuation 交给收它的地方,返回调度器取任务继续
关于 await/async 不知道能不能完全只用 CPS 变换来实现(反正我觉得实现起来枚举语法生成很复杂),但完整的协程是可以的。
duangsuse::Echo
#Kotlin #code #coroutine suspend fun main() = coroutineScope { for (i in 0 until 10) launch { delay(1000L - i*10); print("$i ") } } 提问:为什么结果是 9 downTo 0 ?launch 的里面用了 coroutine 特性,但为什么 main 也是 suspend fun? 如果只是单线程,是怎么在最后才输出第一次的 $i 的?
#Kotlin #coroutine 应该说有了可以挂起恢复的协程后, launch 里面的东西就可以理解为「被添加的Task」吧(此例只是闭包住了变量
第一个 async fun
这个 launch 本身就是独立于 for (i in iprog) 顺序的,不是说得 i=9 的 launch 完了才能发 i=8 的,而 suspend fun() {} 的独立性可以理解为 #TypeScript 式的 async state machine 基本就是单独的闭包了,调度分次不会互相冲突。(或者根本是独立的程序流?)
i
),由线程(池)上执行的调度器来运行它们,类似于 event loop 这样第一个 async fun
delay
本身也是调度器操作,不是 Thread.sleep
不会休眠线程,是完全不同的概念,当然不会卡死调度器,举个例子:var t0 = time(); var t1:Long
for (task in cyclic(tasks)) {
t1 = time()
if (task.delay>=0) task.delay -= (t1-t0)
else { task.run() }
t0 = t1
}
这个 launch 本身就是独立于 for (i in iprog) 顺序的,不是说得 i=9 的 launch 完了才能发 i=8 的,而 suspend fun() {} 的独立性可以理解为 #TypeScript 式的 async state machine 基本就是单独的闭包了,调度分次不会互相冲突。(或者根本是独立的程序流?)
#coroutine #essay 🤔突然觉得还是 Ruby 的 线程(thread)/纤程(fiber) 翻译得比 Kotlin 的 线程/协程(co-routine) 好
因为从某种意义讲,协程就是用户态线程(虽然本名是“协调分词器和解析器的词条流”来的,现在谁还用routine这个术语啊,都是procedure)
这样的话 thread/fiber 解释信更好,虽然 Ruby 本身的混乱掩盖了它这类闪点
因为从某种意义讲,协程就是用户态线程(虽然本名是“协调分词器和解析器的词条流”来的,现在谁还用routine这个术语啊,都是procedure)
这样的话 thread/fiber 解释信更好,虽然 Ruby 本身的混乱掩盖了它这类闪点