±à¼ÍƼö: |
±¾ÎĴӵײ㿪ʼ½éÉÜгÌ,ÈçºÎ½¨Á¢ÔÚ°²È«ÓÐЧµØ¶Ô
RESTful ·þÎñ½øÐжà´Îµ÷ÓõĹ淶ÐÔ£¬Ï£ÍûÄܶÔÄúÓÐËù°ïÖú¡£
±¾ÎÄÀ´×ÔÓÚInfoQ£¬ÓÉ»ðÁú¹ûÈí¼þAlice±à¼¡¢ÍƼö¡£ |
|
±¾ÎÄÒªµã
JVM ²¢Ã»ÓÐÌṩ¶Ôг̵ÄÔÉúÖ§³Ö
Kotlin ÔÚ±àÒëÆ÷ÖÐʵÏÖгÌÊÇͨ¹ý½«Æäת»»ÎªÒ»¸ö״̬»úʵÏÖµÄ
Kotlin ΪʵÏÖʹÓÃÁËÒ»¸ö¹Ø¼ü×Ö£¬ÆäÓà¶¼ÊÇͨ¹ý¿âÀ´Íê³ÉµÄ
Kotlin ʹÓÃÁ¬Ðø´«µÝ·ç¸ñ£¨Continuation Passing Style£¬CPS£©À´ÊµÏÖгÌ
г̻áʹÓõ½ Dispatcher£¬ËùÒÔÔÚ JavaFX¡¢Android¡¢Swing µÈ³¡¾°Ï£¬Ó÷¨ÂÔÓвîÒì¡£
¾¡¹Üг̲¢²»ÊÇÒ»¸öÐµĻ°Ì⣬µ«ËüÊÇÒ»¸öºÜÎüÒýÈ˵ϰÌâ¡£ÕýÈçÆäËûµØ·½µÄÎĵµËùÊö£¬Ð³ÌÔÚÕâЩÄêÀï±»ÖØÐ·¢ÏÖÁ˺ܶà´Î£¬ÌرðÊǵ±ÐèҪijÖÖÐÎʽµÄÇáÁ¿¼¶Ï̺߳Í
/ »òѰÕÒ¡°»Øµ÷µØÓü¡±µÄ½â¾ö·½°¸Ê±¡£
×î½ü£¬Ð³ÌÒѾ³ÉΪ JVM ÉÏ·´Ó¦Ê½±à³ÌµÄÒ»¸öÁ÷ÐеÄÌæ´ú·½°¸¡£Ïñ RxJava »ò Reactor
ÏîÄ¿ÕâÑùµÄ¿ò¼ÜΪ¿Í»§¶ËÌṩÁËÒ»ÖÖ½¥½øÊ½´¦Àí´«ÈëÐÅÏ¢µÄ·½Ê½£¬²¢¶Ô½ÚÁ÷ºÍ²¢ÐÐÌṩÁ˹㷺µÄÖ§³Ö¡£µ«ÊÇ£¬ÎÒÃDZØÐëÎ§ÈÆ·´Ó¦Á÷µÄº¯Êýʽ²Ù×÷À´Öع¹´úÂ룬ÔÚÐí¶àÇé¿öÏ£¬Õâô×öµÄ³É±¾´óÓÚÊÕÒæ¡£
¾ÙÀýÀ´½²£¬ÕâÊÇ Android ÉçÇøÐèÒª¸ü¼òµ¥Ìæ´ú·½°¸µÄÔÒò¡£Kotlin ÓïÑÔÒýÈëгÌ×÷ΪʵÑéÐÔµÄÌØÐÔÒÔÂú×ã¸ÃÐèÇó£¬ÔÚһЩ¸Ä½øÖ®ºó£¬ËüÃdzÉΪ¸ÃÓïÑÔ
1.3 °æ±¾µÄ¹Ù·½ÌØÐÔ¡£Kotlin г̵ÄÓ¦ÓÃÒѾ´Ó UI ¿ª·¢À©Õ¹µ½·þÎñÆ÷¶Ë¿ò¼Ü (Èç Spring
5 ÖÐÌí¼ÓµÄÖ§³Ö)£¬ÉõÖÁ°üÀ¨Ïñ Arrow(ͨ¹ý Arrow Fx ) ÕâÑùµÄº¯Êýʽ¿ò¼Ü¡£
Àí½âг̵ÄÌôÕ½
ÁîÈËÒź¶µÄÊÇ£¬Àí½âг̲¢²»ÊÇÒ»¼þÈÝÒ×µÄÈÎÎñ¡£¾¡¹ÜÓÐÐí¶à Kotlin ר¼ÒËù×öµÄ¹ØÓÚг̵ÄÑݽ²£¬ÆäÖкܶ඼ÊÇÆô·¢ÐԵIJ¢ÇÒ°üº¬·Ç³£¶àµÄÐÅÏ¢£¬µ«ÊÇÏëÒª¼òµ¥µØÖªµÀгÌÊÇʲô£¨»òÕßËü¸ÃÔõÑùʹÓ㩲¢²»ÈÝÒס£Äã¿ÉÄÜ»á˵г̾ÍÊDz¢Ðбà³ÌµÄµÈ¼ÛÆ·¡£
µ¼Ö¸ÃÎÊÌâµÄ²¿·ÖÔÒòÔÚÓڵײãʵÏÖ¡£ÔÚ Kotlin гÌÖУ¬±àÒëÆ÷ֻʵÏÖÁËÒ»¸ösuspend¹Ø¼ü×Ö£¬ÆäËûµÄÊÂÇé¶¼ÊÇÓÉг̿⴦ÀíµÄ¡£Òò´Ë£¬Kotlin
г̷dz£Ç¿´óºÍÁé»î£¬µ«ÔڽṹÉÏÈ´²»ÄÇô¹Ì¶¨¡£¶ÔÓÚ³õѧÕßÀ´Ëµ£¬ÕâÊÇÒ»¸öѧϰµÄÕϰ£¬ÒòΪËûÃÇѧϰµÄ×îºÃ·½·¨ÊÇ×ñѼáʵµÄÖ¸µ¼·½ÕëºÍÑϸñµÄÔÔò¡£±¾ÎÄ»á´Óµ×²ã¿ªÊ¼½éÉÜг̣¬Ï£ÍûÄܹ»Îª¶ÁÕßÌṩÕâÑùµÄ»ù´¡ÖªÊ¶¡£
ÎÒÃǵÄʾÀýÓ¦Ó㨷þÎñÆ÷¶Ë£©
ÎÒÃǵÄÓ¦ÓóÌÐò½«½¨Á¢ÔÚ°²È«ÓÐЧµØ¶Ô RESTful ·þÎñ½øÐжà´Îµ÷ÓõĹ淶ÐÔ£¨canonical£©ÎÊÌâÖ®ÉÏ¡£ÎÒÃǽ«²¥·Å
Where¡¯s Waldo µÄÒ»¸öÎı¾°æ±¾¡ª¡ªÔÚÕâ¸ö°æ±¾ÖУ¬Óû§×ñÑһϵÁеÄÃû³Æ£¬Ö±µ½ËûÃÇÕÒµ½¡°Waldo¡±¡£
ÏÂÃæÊÇÍêÕûµÄ RESTful ·þÎñ£¬ËüÊÇʹÓà Http4k ±àдµÄ¡£Http4k ÊÇÓÉ Marius
Eriksen ׫дµÄÖøÃûÂÛÎÄÖÐÃèÊöµÄº¯Êýʽ·þÎñÆ÷¼Ü¹¹µÄKotlin °æ±¾¡£¸ÃʵÏÖ´æÔÚÐí¶àÆäËûÓïÑԵİ汾£¬°üÀ¨Scala£¨
Http4s £©ºÍ Java 8 »ò¸ü¸ß°æ±¾£¨ Http4j £©¡£
ÕâÀïÖ»ÓÐÒ»¸ö¶Ëµã£¬Ëüͨ¹ý Map ʵÏÖÁËÒ»¸öÃû×ÖµÄÁ´¡£¸ø¶¨Ò»¸öÃû×Ö£¬ÎÒÃÇҪôÒÔ
200 ״̬Âë·µ»ØÆ¥ÅäµÄÖµ£¬ÒªÃ´ÒÔ 404 ״̬Âë·µ»ØÒ»Ìõ´íÎóÐÅÏ¢¡£
fun main() {
val names = mapOf( "Jane" to "Dave",
"Dave" to "Mary", "Mary"
to "Pete", "Pete" to "Lucy",
"Lucy" to "Waldo"
)
val lookupName = { request: Request ->
val name = request.path("name")
val headers = listOf("Content-Type"
to "text/plain")
val result = names[name]
if (result != null) {
Response(OK)
.headers(headers)
.body(result)
} else {
Response(NOT_FOUND)
.headers(headers)
.body("No match for $name")
}
}
routes( "/wheresWaldo" bind routes(
"/{name:.*}" bind Method.GET to lookupName
)
).asServer(Netty(8080))
.start()
} |
ʵ¼ÊÉÏ£¬ÎÒÃÇÏ£Íû¿Í»§¶Ë·¢ËÍÈçϵÄÇëÇóÁ´:

ÎÒÃǵÄʾÀýÓ¦Ó㨿ͻ§¶Ë£©
ÎÒÃǵĿͻ§¶ËÓ¦Óý«»á»ùÓÚ JavaFX ¿âÀ´´´½¨Óû§½çÃæ¡£µ«ÊÇ£¬ÎªÁ˼ò»¯ÎÒÃǵÄÈÎÎñ²¢±ÜÃâ²»±ØÒªµÄϸ½Ú£¬ÎÒÃǽ«»áʹÓÃ
TornadoFX £¬ËüÔÚ JavaFX Ö®ÉÏÌṩÁËÒ»¸ö Kotlin DSL¡£
ÈçÏÂÊǿͻ§¶ËÊӽǵÄÍêÕû¶¨Ò壺
class HelloWorldView:
View("Coroutines Client UI") {
private val finder: HttpWaldoFinder by inject()
private val inputText = SimpleStringProperty("Jane")
private val resultText = SimpleStringProperty("")
override val root = form {
fieldset("Lets Find Waldo") {
field("First Name:") {
textfield().bind(inputText)
button("Search") {
action {
println("Running event handler".addThreadId())
searchForWaldo()
}
}
}
field("Result:") {
label(resultText)
}
}
}
private fun searchForWaldo() {
GlobalScope.launch(Dispatchers.Main) {
println("Doing Coroutines".addThreadId())
val input = inputText.value
val output = finder.wheresWaldo(input)
resultText.value = output
}
}
}class HelloWorldView: View("Coroutines Client
UI") { private val finder: HttpWaldoFinder
by inject() private val inputText = SimpleStringProperty("Jane")
private val resultText = SimpleStringProperty("")
override val root = form { fieldset("Lets
Find Waldo") { field("First Name:")
{ textfield().bind(inputText) button("Search")
{ action { println("Running event handler".addThreadId())
searchForWaldo() } } } field("Result:")
{ label(resultText) } } } private fun searchForWaldo()
{ GlobalScope.launch(Dispatchers.Main) { println("Doing
Coroutines".addThreadId()) val input = inputText.value
val output = finder.wheresWaldo(input) resultText.value
= output } } |
ÎÒÃÇ»¹»áʹÓÃÈçϵĸ¨Öúº¯Êý×÷Ϊ String ÀàÐ͵ÄÀ©Õ¹£º
fun String.addThreadId()
= "$this on thread ${Thread.currentThread().id}" |
ÔÚÔËÐеÄʱºò£¬UI ÈçÏÂËùʾ£º

µ±Óû§µã»÷°´Å¥µÄʱºò£¬ÎÒÃǻᴴ½¨Ò»¸öеÄг̣¬²¢Í¨¹ý¡°HttpWaldoFinder¡±ÀàÐ͵ķþÎñ¶ÔÏó·ÃÎÊ
RESTful ¶Ëµã¡£
Kotlin г̴æÔÚÓÚÒ»¸ö¡°CoroutineScope¡±ÖУ¬¶øºóÕßÓֻᷴ¹ýÀ´ºÍijÖÖ Dispatcher
¹ØÁª£¬Dispatcher ´ú±íÁ˵ײãµÄ²¢·¢Ä£ÐÍ¡£²¢·¢Ä£ÐÍͨ³£ÊÇÒ»¸öÏ̳߳أ¬µ«ÊÇ»áÓÐËù²îÒì¡£
¾ßÌåÄÄЩ Dispatcher ¿ÉÓÃÈ¡¾öÓÚ Kotlin ´úÂëÔËÐеĻ·¾³¡£Main Dispatcher
±íʾ UI ¿âµÄʼþ´¦ÀíỊ̈߳¬Òò´Ë (ÔÚ JVM ÉÏ) Ö»ÄÜÔÚ Android¡¢JavaFX ºÍ Swing
ÖÐʹÓá£×î³õ£¬Kotlin Native ¸ù±¾²»Ö§³Öг̵ĶàÏ̴߳¦Àí£¬µ«ÕâÖÖÇé¿öÕýÔڸı䡣ÔÚ·þÎñÆ÷¶Ë£¬ÎÒÃÇ¿ÉÒÔ×Ô¼ºÒýÈëг̣¬µ«ÊÇÔÚÔ½À´Ô½¶àµÄÇé¿öÖУ¬Ð³ÌĬÈϾÍÊÇ¿ÉÓõ쬱ÈÈçÔÚ
Spring 5 ÖС£
ÔÚµ÷ÓÃ¹ÒÆð£¨suspending£©·½·¨Ö®Ç°£¬ÎÒÃDZØÐ뽫г̡¢¡°CoroutineScope¡±ºÍ¡°Dispatche¡±×¼±¸¾ÍÐ÷¡£Èç¹ûÕâÊdzõʼµ÷Óõϰ£¨ÈçÉÏÃæµÄ´úÂëËùʾ£©£¬ÎÒÃÇ¿ÉÒÔͨ¹ý¡°Ð³Ì¹¹ÔìÕß¡±º¯Êý£¬Èç¡°launch¡±ºÍ¡°async¡±£¬Æô¶¯¸Ã¹ý³Ì¡£
²»¹ÜÊǵ÷ÓÃг̹¹½¨Õߺ¯Êý£¬»¹ÊÇÏñ¡°withContext¡±ÕâÑùµÄ×÷ÓÃÓòº¯Êý£¬¶¼»á´´½¨Ò»¸öеġ°CoroutineScope¡±¡£ÔÚ¸Ã×÷ÓÃÓòÖУ¬ÈÎÎñÌåÏÖΪ¡°Job¡±ÊµÀýµÄ²ã¼¶½á¹¹¡£
ËüÃÇÓÐһЩºÜÓÐÒâ˼µÄÊôÐÔ£¬¼´£º
Job »áµÈ´ýÆä¿éÄÚËùÓÐгÌÍê³Éºó²ÅÄÜÍê³É×Ô¼º¡£
È¡ÏûÒ»¸ö Job »áµ¼ÖÂÆäËùÓеÄ×Ó Job ¶¼±»È¡Ïû¡£
×Ó Job µÄʧ°Ü»òÈ¡Ïû»á´«²¥ÖÁ¸¸ Job¡£
ÕâÑùÉè¼ÆµÄÄ¿µÄÊDZÜÃâ²¢·¢±à³ÌÖеij£¼ûÎÊÌ⣬±ÈÈçɱËÀ¸¸ Job µÄʱºòûÓÐÖÕ½áÆä×Ó Job¡£
·ÃÎÊ REST ¶ËµãµÄ·þÎñ
ÈçÏÂÊÇ HttpWaldoFinder ·þÎñµÄÍêÕû´úÂ룺
class HttpWaldoFinder
: Controller(), WaldoFinder {
override suspend fun wheresWaldo(starterName:
String): String {
val firstName = fetchNewName(starterName)
println("Found $firstName name".addThreadId())
val secondName = fetchNewName(firstName)
println("Found $secondName name".addThreadId())
val thirdName = fetchNewName(secondName)
println("Found $thirdName name".addThreadId())
val fourthName = fetchNewName(thirdName)
println("Found $fourthName name".addThreadId())
return fetchNewName(fourthName)
}
private suspend fun fetchNewName(inputName: String):
String {
val url = URI("http://localhost:8080/wheresWaldo/$inputName")
val client = HttpClient.newBuilder().build()
val handler = HttpResponse.BodyHandlers.ofString()
val request = HttpRequest.newBuilder().uri(url).build()
return withContext<String>(Dispatchers.IO)
{
println("Sending HTTP Request for $inputName".addThreadId())
client
.send(request, handler)
.body()
}
}
} |
¡°fetchNewName¡±º¯Êý»á½ÓÊÕÒ»¸öÒÑÖªµÄÃû×Ö£¬²¢²éѯ¶Ëµã»ñÈ¡¹ØÁªµÄÃû×Ö¡£ÕâÊÇͨ¹ýʹÓá°HttpClient¡±ÀàÐÍÀ´ÊµÏֵ쬏ÃÀàÐÍÊÇ´Ó
Java 11 ¿ªÊ¼×÷Ϊ±ê×¼µÄ¡£Êµ¼ÊµÄ HTTP GET »áÔÚÒ»¸öеÄ×ÓгÌÖÐÔËÐУ¬¸Ã×Óг̻áʹÓÃ
IO Dispatcher¡£ËüµÄ±íÏÖÐÎʽÊÇÒ»¸öΪ³¤Ê±¼äÔËÐеĻ£¨ÈçÍøÂçµ÷Óã©ÓÅ»¯µÄÏ̳߳ء£
¡°wheresWaldo¡±º¯Êý»á¸ù¾ÝÃû×ÖÁ´Ö´ÐÐÎå´Î£¬ÒÔ±ãÓÚ£¨¾¡Á¦£©ÕÒµ½ Waldo¡£ÎÒÃÇËæºó½«»á·Ö½âÉú³ÉµÄ×Ö½ÚÂ룬ËùÒÔÎÒÃÇÈÃʵÏÖ¾¡¿ÉÄܵؼòµ¥¡£ÎÒÃǸÐÐËȤµÄÊÇ£¬Ã¿´Îµ÷Óá°fetchNewName¡±¶¼»áµ¼Öµ±Ç°Ð³ÌÔÚ×ÓгÌÔËÐÐʱ±»¹ÒÆð¡£ÔÚÕâ¸öÌØÊⳡ¾°Ï£¬¸¸
Job ÔËÐÐÔÚ Main Dispatcher ÉÏ£¬¶ø×Ó Job ÔËÐÐÔÚ IO Dispatcher
ÉÏ¡£Òò´Ë£¬µ±×Ó Job Ö´ÐÐ HTTP ÇëÇóʱ£¬UI ʼþ´¦ÀíÏ̻߳ᱻÊͷųöÀ´´¦ÀíÓëÊÓͼµÄÓû§½»»¥¡£ÈçÏÂͼËùʾ¡£

IntelliJ »áΪÎÒÃÇչʾºÎʱ·¢Æð¹ÒÆðµ÷Óã¬Òò´Ë»áÔÚг̼äת»»¿ØÖÆ¡£ÐèҪעÒ⣬Èç¹ûÎÒÃÇûÓÐÇл»
Dispatcher µÄ»°£¬ÄÇ·¢Æðµ÷Óò»Ò»¶¨»á´´½¨ÐµÄг̡£µ±Ò»¸ö¹ÒÆðº¯Êýµ÷ÓÃÁíÒ»¸ö¹ÒÆðº¯Êýʱ£¬¿ÉÄÜ»áÔÚÏàͬµÄгÌÖмÌÐø£¬Èç¹ûÎÒÃÇÕæµÄÏ£Íû±£³ÖÔÚͬһ¸öÏß³ÌÉÏ£¬ÄÇôÕâµÄÈ·¾ÍÊÇÎÒÃÇÏëÒªµÄÐÐΪ¡£

µ±ÎÒÃÇÖ´Ðпͻ§¶ËµÄʱºò£¬ÈçϾÍÊÇ¿ØÖÆÌ¨µÄÊä³ö£º

ÎÒÃÇ¿ÉÒÔ¿´µ½£¬ÔÚÕâ¸öÌØÊâµÄ³¡¾°Ï£¬Main Dispatcher/UI ʼþ´¦ÀíÆ÷ÔËÐÐÔÚ 17 ºÅÏß³ÌÉÏ£¬¶ø
IO Dispatcher ÔËÐÐÔÚÏ̳߳ØÉÏ£¬°üÀ¨ 24 ºÅºÍ 26 ºÅÏ̡߳£
¿ªÊ¼ÎÒÃǵĵ÷²é
½èÖú IntelliJ ×Ô´øµÄ×Ö½ÚÂë·Ö½â¹¤¾ß£¬ÎÒÃÇ¿ÉÒÔ¿´³öµ½µ×·¢ÉúÁËʲô¡£ÁíÍ⣬ÎÒÃÇÒ²¿ÉÒÔʹÓà JDK
ÌṩµÄ±ê×¼¡°javap¡±¹¤¾ß¡£

ÎÒÃÇ¿ÉÒÔ¿´µ½¡°HttpWaldoFinder¡±µÄ·½·¨¸Ä±äÁËÆäÇ©Ãû£¬ËùÒÔËüÃÇ¿ÉÒÔ½ÓÊÜÒ»¸ö
Continuation ¶ÔÏó×÷ΪÆä¶îÍâµÄ²ÎÊý£¬²¢ÇÒ·µ»ØÄ³ÖÖͨÓõĶÔÏó¡£
public final
class HttpWaldoFinder extends Controller implements
WaldoFinder {
public Object wheresWaldo(String a, Continuation
b)
final synthetic Object fetchNewName(String a,
Continuation b)
} |
ÏÖÔÚ£¬ÎÒÃÇÉîÈë´úÂë¿´Ò»ÏÂÕâЩ·½·¨¶¼Ìí¼ÓÁËЩʲô£¬²¢²ûÊö¡°Continuation¡±ÊÇʲôÒÔ¼°ÏÖÔÚ·µ»ØµÄÊÇʲô¡£
Á¬Ðø´«µÝ·ç¸ñ£¨Coninuation Passing Style£¬CPS£©
°´ÕÕ Kotlin ±ê×¼»¯¹ý³Ì¶ÔгÌÌáÒéµÄÎĵµÃèÊö£¬Ð³ÌµÄʵÏÖÊÇ»ùÓÚÁ¬Ðø´«µÝ·ç¸ñ (Continuation
Passing Style£¬CPS) µÄ¡£»áÓÐÒ»¸ö continuation ¶ÔÏóÀ´´æ´¢º¯ÊýÔÚ¹ÒÆð½×¶ÎËùÐèµÄ״̬¡£
ÔÚ±¾ÖÊÉÏ£¬¹ÒÆðº¯ÊýµÄÿ¸ö¾Ö²¿±äÁ¿¶¼»á³ÉΪ continuation µÄÒ»¸ö×ֶΡ£ÁíÍ⣬»¹ÐèÒª´´½¨×Ö¶ÎÀ´´æ´¢ËùÓеIJÎÊýºÍµ±Ç°¶ÔÏó£¨Èç¹ûº¯ÊýÊÇ·½·¨µÄ»°£©¡£ËùÒÔ£¬Ò»¸ö¹ÒÆð·½·¨Èç¹ûÓÐËĸö²ÎÊýºÍÎå¸ö¾Ö²¿±äÁ¿µÄ»°£¬continuation
ÖÁÉÙÒªÓÐ 10 ¸ö×ֶΡ£
ÔÚ¡°HttpWaldoFinder¡±µÄ¡°wheresWaldo¡±·½·¨ÖУ¬ÓÐÒ»¸ö²ÎÊýºÍËĸö±¾µØ±äÁ¿£¬ËùÒÔÎÒÃÇÔ¤ÆÚ
continuation ʵÏÖÀàÐÍ»áÓÐÁù¸ö×ֶΡ£Èç¹ûÎÒÃǽ« Kotlin ±àÒëÆ÷Éú³ÉµÄ×Ö½ÚÂë·Ö½â³É
Java Ô´ÂëµÄ»°£¬¾Í»á·¢ÏÖÊÂʵȷʵÈç´Ë£º
$continuation
= new ContinuationImpl($completion) {
Object result;
int label;
Object L$0;
Object L$1;
Object L$2;
Object L$3;
Object L$4;
Object L$5;
@Nullable
public final Object invokeSuspend(@NotNull Object
$result) {
this.result = $result;
this.label |= Integer.MIN_VALUE;
return HttpWaldoFinder.this.wheresWaldo((String)null,
this);
}
}; |
¼øÓÚËùÓеÄ×ֶζ¼ÊÇ Object ÀàÐ͵ģ¬ËùÒÔËüÃǸÃÈçºÎʹÓò¢²»Ã÷ÏÔ¡£Ëæ×ŽøÒ»²½Ì½Ë÷£¬ÎÒÃǽ«»á¿´µ½£º
¡°L$0¡±³ÖÓжԡ°HttpWaldoFinder¡±ÊµÀýµÄÒýÓá£ËüʼÖÕ¶¼»á´æÔÚ¡£
¡°L$1¡±³ÖÓС°starterName¡±²ÎÊýµÄÖµ¡£ËüʼÖÕ¶¼»á´æÔÚ¡£
¡°L2¡±µ½¡°L5¡±³ÖÓб¾µØ±äÁ¿µÄÖµ¡£Ëæ×Å´úÂëµÄÖ´ÐУ¬ËüÃǽ«»á½¥½øÊ½µØÌî³ä½øÀ´¡£¡°L$2¡±»á³ÖÓС°firstName¡±µÄÖµ£¬ÒÔ´ËÀàÍÆ¡£
ÎÒÃÇ»¹ÓжîÍâµÄ×ֶδ洢×îÖÕ½á¹û£¬ÓÐÒ»¸öÃûΪ¡°label¡±µÄÓÐȤµÄÕûÐÍ×ֶΡ£
¹ÒÆð»¹ÊDz»¹ÒÆð¡ª¡ªÕâÊÇÒ»¸öÎÊÌâ
µ±ÎÒÃǼì²éÉú³ÉµÄ´úÂëʱ£¬ÐèÒª¼ÇסËüÒª´¦ÀíÁ½¸ö³¡¾°¡£Ã¿µ±Ò»¸ö¹ÒÆðµÄº¯Êýµ÷ÓÃÁíÒ»¸öº¯Êýʱ£¬Ëü¿ÉÄÜ»á¹ÒÆðµ±Ç°µÄг̣¨ÕâÑùÁíÍâÒ»¸öº¯Êý¿ÉÒÔÔÚÏàͬµÄÏß³ÌÉÏÔËÐУ©£¬Ò²¿ÉÄÜÔÚµ±Ç°Ð³Ì»á¼ÌÐøÖ´ÐС£
ÎÒÃÇ¿¼ÂÇÒ»¸ö´ÓÊý¾Ý´æ´¢ÖжÁȡֵµÄ¹ÒÆðº¯Êý¡£µ± I/O ·¢ÉúµÄʱºò£¬ËüºÜ¿ÉÄܻᱻ¹ÒÆð£¬µ«ÊÇËüÒ²¿ÉÄܻỺ´æ½á¹û¡£ºóÐøµ÷ÓÿÉÒÔͬ²½·µ»Ø»º´æµÄÖµ£¬²»ÐèÒªÈÎºÎµÄ¹ÒÆð¡£Kotlin
±àÒëÆ÷ËùÉú³ÉµÄ´úÂë±ØÐëҪͬʱ֧³ÖÕâÁ½ÖÖ·¾¶¡£
Kotlin »áµ÷Õûÿ¸ö¹ÒÆðº¯ÊýµÄ·µ»ØÀàÐÍ£¬ÕâÑùµÄ»°£¬ËüҪô·µ»ØÕæÕýµÄ½á¹û£¬ÒªÃ´·µ»ØÌØÊâµÄÖµ COROUTINE_SUSPENDED¡£Èç¹ûÊǺóÕߵϰ£¬µ±Ç°µÄг̻ᱻ¹ÒÆð¡£ÕâÒ²ÊÇΪʲô¹ÒÆðº¯ÊýµÄ·µ»ØÀàÐÍ´Ó½á¹ûÀàÐͱä³ÉÁË¡°Object¡±¡£
ÔÚÎÒÃǵÄÑùÀýÓ¦ÓÃÖУ¬¡°wheresWaldo¡±»áÖØ¸´µ÷Óá°fetchNewName¡±¡£ÔÚÀíÂÛÉÏ£¬Ã¿´ÎÕâÑùµÄµ÷Óö¼¿ÉÄÜ¹ÒÆð»ò²»¹ÒÆðµ±Ç°µÄг̡£°´ÕÕÎÒÃDZàд¡°fetchNewName¡±µÄ·½Ê½£¬¿ÉÒÔÖªµÀ£¬¹ÒÆðʼÖÕ¶¼»á·¢Éú¡£µ«ÊÇ£¬ÎªÁËÀí½âÉú³ÉµÄ´úÂ룬ÎÒÃDZØÐë¼ÇסËüÐèÒª´¦ÀíËùÓеĿÉÄÜÐÔ¡£
´óµÄ Switch Óï¾äºÍ Label
Èç¹ûÎÒÃǽøÒ»²½²é¿´·Ö½âºóµÄ´úÂ룬»á·¢ÏÖÒ»¸öÒþ²ØÔÚ¶à¸öǶÌ× label
ÖÐµÄ switch Óï¾ä¡£ÕâÊÇÒ»¸ö״̬»úµÄʵÏÖ£¬ÓÃÀ´ÔÚ wheresWaldo() ·½·¨ÖпØÖƲ»Í¬µÄ¹ÒÆðµã¡£ÏÂÃæÊÇÕûÌåµÄ½á¹¹£º
// ³ÌÐòÇåµ¥ 1£ºÉú³ÉµÄ
switch Óï¾äºÍ label
String firstName;
String secondName;
String thirdName;
String fourthName;
Object var11;
Object var10000;
label48: {
label47: {
label46: {
Object $result = $continuation.result;
var11 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
switch($continuation.label) {
case 0:
// Ê¡ÂÔ´úÂë
case 1:
// Ê¡ÂÔ´úÂë
case 2:
// Ê¡ÂÔ´úÂë
case 3:
// Ê¡ÂÔ´úÂë
case 4:
// Ê¡ÂÔ´úÂë
case 5:
// Ê¡ÂÔ´úÂë
default:
throw new IllegalStateException( "call
to 'resume' before 'invoke' with coroutine");
} // ½áÊø switch
// Ê¡ÂÔ´úÂë
} // ½áÊø label 46
// Ê¡ÂÔ´úÂë
} // ½áÊø label 47
// Ê¡ÂÔ´úÂë
} // ½áÊø label 48
// Ê¡ÂÔ´úÂë |
ÎÒÃÇÏÖÔÚ¿ÉÒÔ¿´µ½ continuation ÖС°label¡±×ֶεÄÄ¿µÄÁË¡£µ±Íê³É¡°wheresWaldo¡±µÄ²»Í¬½×¶Îʱ£¬ÎÒÃǽ«»á±ä¸ü¡°label¡±ÖеÄÖµ¡£Ç¶Ì×µÄ
label ´úÂë¿éÖаüº¬ÁËÔʼ Kotlin ´úÂëÀïÃæ¹ÒÆðµãÖ®¼äµÄ´úÂë¿é¡£Õâ¸ö¡°label¡±ÖµÔÊÐíÖØÐ½øÈë¸Ã´úÂë£¬Ìøµ½×îºó¹ÒÆðµÄµØ·½£¨Êʵ±µÄ
case Óï¾ä£©£¬ÒÔ±ãÓÚ´Ó continuation ÖгéÈ¡Êý¾Ý£¬È»ºóÌø×ªµ½ÕýÈ·µÄ label ´úÂë¿é¡£
µ«ÊÇ£¬Èç¹ûËùÓÐµÄ¹ÒÆðµã¶¼Ã»ÓÐÕæÕý¹ÒÆðµÄ»°£¬Õû¸ö´úÂë¿é¿ÉÒÔͬ²½Ö´ÐС£ÔÚÉú³ÉµÄ´úÂëÖУ¬ÎÒÃǾ³£»á¿´µ½ÕâÑùµÄƬ¶Î£º
// ³ÌÐòÇåµ¥ 2£ºÈ·¶¨µ±Ç°µÄгÌÊÇ·ñÓ¦¸Ã¹ÒÆð
if (var10000 == var11) {
return var11;
} |
´ÓÉÏÃæÎÒÃÇ¿ÉÒÔ¿´µ½£¬¡°var11¡±±»ÉèÖóÉÁËCONTINUATION_SUSPENDEDµÄÖµ£¬¶ø¡°var10000¡±±£´æÁ˶ÔÁíÒ»¸ö¹ÒÆðº¯ÊýµÄµ÷Óõķµ»ØÖµ¡£Òò´Ë£¬µ±¹ÒÆð·¢Éúʱ£¬´úÂ뽫·µ»Ø
(ÉÔºó»áÖØÐ½øÈë)£¬Èç¹ûûÓз¢Éú¹ÒÆð£¬Ôò´úÂ뽫ͨ¹ýÇл»µ½Êʵ±µÄ label ¿é¼ÌÐøÖ´Ðк¯ÊýµÄÏÂÒ»²¿·Ö¡£
ÔÙ´ÎÇ¿µ÷£¬Çë¼Çס£¬Éú³ÉµÄ´úÂë²»ÄܼÙÉèËùÓе÷Óö¼½«¹ÒÆð£¬»òÕßËùÓе÷Óö¼½«¼ÌÐøÊ¹Óõ±Ç°µÄг̡£Ëü±ØÐëÄܹ»´¦ÀíÈκοÉÄܵÄ×éºÏ¡£
¸ú×ÙÖ´ÐÐ
µ±ÎÒÃÇ¿ªÊ¼Ö´ÐÐʱ£¬continuation ÖС°label¡±µÄÖµ½«»á±»ÖÃΪÁã¡£ÈçÏÂÊǶÔÓ¦µÄ
switch Óï¾ä·ÖÖ§£º
// ³ÌÐòÇåµ¥ 3£ºswitch
µÄµÚÒ»¸ö·ÖÖ§
case 0:
ResultKt.throwOnFailure($result);
$continuation.L$0 = this;
$continuation.L$1 = starterName;
$continuation.label = 1;
var10000 = this.fetchNewName(starterName, $continuation);
if (var10000 == var11) {
return var11;
}
break; |
ÎÒÃǽ«ÊµÀýºÍ²ÎÊý´æ´¢µ½ÁË continuation ¶ÔÏóÖУ¬È»ºó½« continuation ¶ÔÏ󴫵ݸø¡°fetchNewName¡±¡£ÈçǰÎÄËùÊö£¬±àÒëÆ÷ËùÉú³ÉµÄ¡°fetchNewName¡±°æ±¾ÒªÃ´·µ»ØÊµ¼ÊµÄ½á¹û£¬ÒªÃ´·µ»ØCOROUTINE_SUSPENDEDÖµ¡£
Èç¹ûÐ³Ì¹ÒÆðµÄ»°£¬ÄÇôÎÒÃÇ»á´Óº¯ÊýÖзµ»Ø£¬²¢ÇÒµ±ÎÒÃǻָ´µÄʱºò£¬»áÌøÈë¡°case
1¡±·ÖÖ§¡£Èç¹ûÎÒÃǼÌÐøÊ¹Óõ±Ç°µÄг̣¬ÄÇô»áÌø³ö switch µ½Ä³Ò»¸ö label ´úÂë¿é£¬½øÈëÈçϵĴúÂ룺
// ³ÌÐòÇåµ¥ 4£ºµÚ¶þ´Îµ÷Óá°fetchNewName¡±
firstName = (String)var10000;
secondName = UtilsKt.addThreadId("Found "
+ firstName + " name");
boolean var13 = false;
System.out.println(secondName);
$continuation.L$0 = this;
$continuation.L$1 = starterName;
$continuation.L$2 = firstName;
$continuation.label = 2;
var10000 = this.fetchNewName(firstName, $continuation);
if (var10000 == var11) {
return var11;
} |
ÒòΪÎÒÃÇÖªµÀ¡°var10000¡±°üº¬ÁËÎÒÃÇÆÚÍûµÄ·µ»ØÖµ£¬ËùÒÔÎÒÃÇ¿ÉÒÔ½«Æäת»»³ÉÕýÈ·µÄÀàÐͲ¢´æ´¢µ½¾Ö²¿±äÁ¿¡°firstName¡±ÖС£Ëæºó£¬Éú³ÉµÄ´úÂë»áʹÓá°secondName¡±À´´æ´¢Ïß³Ì
id Á¬½ÓµÄ½á¹û£¬²¢ÇÒ½«Æä´òÓ¡Á˳öÀ´¡£
ÎÒÃǸüÐÂÁË continuation ÖеÄ×ֶΣ¬Ìí¼ÓÁË·þÎñÆ÷¼ìË÷µ½µÄÖµ¡£×¢Ò⣬¡°label¡±µÄÖµÏÖÔÚÒѾÊÇ
2 ÁË¡£Ëæºó£¬ÎÒÃǵÚÈý´Îµ÷Óá°fetchNewName¡±¡£
µÚÈý´Îµ÷Óá°fetchNewName¡±¡ª¡ªÎÞ¹ÒÆð
ÎÒÃÇÐèÒªÔٴλùÓÚ¡°fetchNewName¡±·µ»ØµÄÖµ×ö³öÑ¡Ôñ£¬Èç¹û·µ»ØµÄÖµÊÇCOROUTINE_SUSPENDEDµÄ»°£¬ÎÒÃÇ»á´Óµ±Ç°º¯Êý·µ»Ø¡£µ±ÏÂÒ»´Îµ÷ÓÃʱ£¬ÎÒÃÇÒª×ñÑ
switch µÄ¡°case 2¡±·ÖÖ§¡£
Èç¹ûÎÒÃǼÌÐøÊ¹Óõ±Ç°Ð³ÌµÄ»°£¬ÄÇô½«»áÖ´ÐÐÈçϵĴúÂë¿é¡£ÎÒÃÇ¿ÉÒÔ¿´µ½ËüÓëÉÏÃæµÄ´úÂëÊÇÏàͬµÄ£¬Ö»²»¹ýÎÒÃÇÏÖÔÚÒªÓиü¶àµÄÊý¾Ý´æ´¢µ½
continuation ÖС£
// ³ÌÐòÇåµ¥ 4£ºµÚÈý´Îµ÷Óá°fetchNewName¡±
secondName = (String)var10000;
thirdName = UtilsKt.addThreadId("Found "
+ secondName + " name");
boolean var14 = false;
System.out.println(thirdName);
$continuation.L$0 = this;
$continuation.L$1 = starterName;
$continuation.L$2 = firstName;
$continuation.L$3 = secondName;
$continuation.label = 3;
var10000 = this.fetchNewName(secondName, (Continuation)$continuation);
if (var10000 == var11) {
return var11;
} |
ÕâÖÖģʽÔÚºóÐøµÄµ÷ÓÃÖлáÖØ¸´£¨¼Ù¶¨Ê¼ÖÕûÓзµ»ØCOROUTINE_SUSPENDED£©£¬Ö±µ½µ½´ïÖÕµãΪֹ¡£
µÚÈý´Îµ÷Óá°fetchNewName¡±¡ª¡ª´øÓÐ¹ÒÆð
»òÕߣ¬Èç¹ûгÌÒѾ±»¹ÒÆðµÄ»°£¬ÄÇô½«»áÔËÐÐÈçϵĴúÂë¿é£º
// ³ÌÐòÇåµ¥ 5£ºswitch
µÄµÚÈý¸ö·ÖÖ§
case 2:
firstName = (String)$continuation.L$2;
starterName = (String)$continuation.L$1;
this = (HttpWaldoFinder)$continuation.L$0;
ResultKt.throwOnFailure($result);
var10000 = $result;
break label46; |
ÎÒÃǽ« continuation ÖеÄÖµ³éÈ¡µ½º¯ÊýµÄ¾Ö²¿±äÁ¿ÖС£ËæºóʹÓÃÒ»¸ö label ÐÎʽµÄ break
ʹִÐÐÌø×ªÖÁǰÊöµÄ³ÌÐòÇåµ¥ 4 ÖС£ËùÒÔ×îÖÕ£¬ÎÒÃÇ»áÔÚÏàͬµÄµØ·½½áÊø¡£
×ܽáÖ´Ðйý³Ì
ÏÖÔÚ£¬ÎÒÃÇ¿ÉÒÔÖØÐ¿´Ò»Ï³ÌÐòÇåµ¥µÄ´úÂë½á¹¹£¬²¢ÔÚÕûÌåÉÏÃèÊöÒ»ÏÂÿ¸öÇøÓòÖж¼·¢ÉúÁËʲô£º
// ³ÌÐòÇåµ¥ 6£ºÉî¶È½âÎöÉú³ÉµÄ
switch Óï¾äºÍ label
String firstName;
String secondName;
String thirdName;
String fourthName;
Object var11;
Object var10000;
label48: {
label47: {
label46: {
Object $result = $continuation.result;
var11 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
switch($continuation.label) {
case 0:
// ½« label ÉèÖÃΪ 1£¬Èç¹û·µ»Ø¹ÒÆðµÄ»°£¬µÚÒ»´Îµ÷Óá°fetchNewName¡±
// ·ñÔò£¬´Ó switch ÖÐ break Í˳ö
case 1:
// ´Ó continuation ÖгéÈ¡²ÎÊý
// ´Ó switch ÖÐ break Í˳ö
case 2:
// ´Ó continuation ÖгéÈ¡²ÎÊýºÍµÚÒ»¸ö½á¹û
// Ìø×ªµ½Íâ±ßµÄ¡°label46¡±
case 3:
// ´Ó continuation ÖгéÈ¡²ÎÊý£¬µÚÒ»¸öºÍµÚ¶þ¸ö½á¹û
// Ìø×ªµ½Íâ±ßµÄ¡°label47¡±
case 4:
// ´Ó continuation ÖгéÈ¡²ÎÊý£¬µÚÒ»¸ö¡¢µÚ¶þ¸öºÍµÚÈý¸ö½á¹û
// Ìø×ªµ½Íâ±ßµÄ¡°label48¡±
case 5:
// ´Ó continuation ÖгéÈ¡²ÎÊý£¬µÚÒ»¸ö¡¢µÚ¶þ¸ö¡¢µÚÈý¸öºÍµÚËĸö½á¹û
// ·µ»Ø×îºóµÄ½á¹û
default:
throw new IllegalStateException( "call
to 'resume' before 'invoke' with coroutine");
} // ½áÊø switch
// ´æ´¢²ÎÊýºÍµÚÒ»¸ö½á¹ûµ½ continuation ÖÐ
// Èç¹û·µ»Ø¹ÒÆðµÄ»°£¬½« label ÉèÖÃΪ 2 ²¢¶Ô¡°fetchNewName¡±½øÐеڶþ´Îµ÷ÓÃ
// ·ñÔòµÄ»°¼ÌÐø½øÐÐ
} // ½áÊø label 46
// ´æ´¢²ÎÊý¡¢µÚÒ»¸ö½á¹ûºÍµÚ¶þ¸ö½á¹ûµ½ continuation ÖÐ
// Èç¹û·µ»Ø¹ÒÆðµÄ»°£¬½« label ÉèÖÃΪ 3 ²¢¶Ô¡°fetchNewName¡±½øÐеÚÈý´Îµ÷ÓÃ
// ·ñÔòµÄ»°¼ÌÐø½øÐÐ
} // ½áÊø label 47
// ´æ´¢²ÎÊý¡¢µÚÒ»¸ö½á¹û¡¢µÚ¶þ¸ö½á¹ûºÍµÚÈý¸ö½á¹ûµ½ continuation ÖÐ
// Èç¹û·µ»Ø¹ÒÆðµÄ»°£¬½« label ÉèÖÃΪ 4 ²¢¶Ô¡°fetchNewName¡±½øÐеÚËĴε÷ÓÃ
// ·ñÔòµÄ»°¼ÌÐø½øÐÐ
} // ½áÊø label 48
// ´æ´¢²ÎÊý¡¢µÚÒ»¸ö½á¹û¡¢µÚ¶þ¸ö½á¹û¡¢µÚÈý¸ö½á¹ûºÍµÚËĸö½á¹ûµ½ continuation
ÖÐ
// ½« label ÉèÖÃΪ 5 ²¢¶Ô¡°fetchNewName¡±½øÐеÚÎå´Îµ÷ÓÃ
// ·µ»Ø×îÖÕ½á¹û»ò COROUTINE_SUSPENDED |
½á¹û
Õâ¸ö´úÂë¿âÀí½âÆðÀ´²¢²»¼òµ¥¡£ÎÒÃÇ·ÖÎöÁË×Ö½ÚÂë·Ö½âµÃµ½µÄ Java ´úÂ룬ÕâЩ×Ö½ÚÂëÊÇÓÉ Kotlin
±àÒëÆ÷ÖеĴúÂëÉú³ÉÆ÷Ëù²úÉúµÄ¡£Õâ¸ö´úÂëÉú³ÉÆ÷µÄÊä³öÔÚÉè¼ÆÊ±¿¼ÂǵÄÊÇЧÂʺÍ×îС»¯£¬¶ø²»ÊÇ¿ÉÀí½âÐÔ¡£
µ«ÊÇ£¬ÎÒÃÇ¿ÉÒԵóöһЩÓÐÓõĽáÂÛ£º
²¢Ã»ÓÐʲôħ·¨¡£µ±¿ª·¢ÈËÔ±µÚÒ»´Î¿ªÊ¼Ñ§Ï°Ð³Ìʱ£¬ºÜÈÝÒ×»áÈÏΪÓÐÐ©ÌØÊâµÄ¡°Ä§·¨¡±½«ËùÓеÄÕâЩÊÂÇéÁ¬½ÓÔÚÁËÒ»Æð¡£ÎÒÃÇ¿ÉÒÔ¿´µ½£¬Éú³ÉµÄ´úÂëֻʹÓÃÁËһЩ¹ý³Ìʽ±à³ÌµÄ»ù±¾¹¹½¨¿é£¬±ÈÈçÌõ¼þÓï¾äºÍ´øÓÐ
label µÄ break¡£
ʵÏÖÊÇ»ùÓÚ continuation µÄ¡£ÔÚ×î³õµÄ KEEP ÌáÒéÖУ¬º¯Êý¹ÒÆðºÍ»Ö¸´µÄ·½·¨Êǽ«º¯ÊýµÄ״̬»º´æÔÚÒ»¸ö¶ÔÏóÖС£Òò´Ë£¬¶ÔÓÚÿ¸ö¹ÒÆðº¯Êý£¬±àÒëÆ÷½«´´½¨Ò»¸ö°üº¬
N ¸ö×Ö¶ÎµÄ continuation ÀàÐÍ£¬ÆäÖÐ N ÊDzÎÊýµÄÊýÁ¿¼ÓÉÏ×Ö¶ÎÊýÔÙ¼ÓÉÏ 3¡£×îºóµÄÈý¸ö×ֶα£´æµ±Ç°¶ÔÏó¡¢×îÖÕ½á¹ûºÍË÷Òý¡£
Ö´ÐÐʼÖÕ×ñÑÒ»¸ö±ê×¼µÄģʽ¡£Èç¹û´Ó¹ÒÆðÖлָ´£¬ÄÇôÎÒÃÇҪʹÓà continuation µÄ¡°label¡±×Ö¶ÎÌø×ªµ½
switch Óï¾äµÄÊʵ±·ÖÖ§¡£ÔÚÕâ¸ö·ÖÖ§ÖУ¬ÎÒÃÇ´Ó continuation ¶ÔÏó¼ìË÷µ½Ä¿Ç°ÎªÖ¹ÒѾÕÒµ½µÄÊý¾Ý£¬È»ºóʹÓÃÒ»¸ö´øÓÐ
label µÄ break Ìø×ªµ½Ã»Óз¢Éú¹ÒÆðµÄ´úÂ룬ÕâЩ´úÂë±¾À´ÊÇÒªÖ±½ÓÖ´Ðеġ£
|