LoginSignup
16
19

More than 5 years have passed since last update.

CoroutineがネットワークI/O待ちになったときに他のCoroutineが実行されるのか

Last updated at Posted at 2019-02-20

Coroutine(コルーチン)はネットワークI/O待ちになると他のCoroutineが実行されるのか?

・・・という疑問を解消するために少し実験してみました。

AsyncTask の場合

まずはさくっと AsyncTask で実験します。

事前に適当な PHP スクリプトを置いておきます。

sleep.php
<?php
sleep(2);
echo date(DATE_ATOM);
?>
MainActivity.kt
class MainActivity : AppCompatActivity() {

    private val tag = javaClass.simpleName

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        client = OkHttpClient.Builder()
            .connectTimeout(10, TimeUnit.SECONDS)
            .readTimeout(10, TimeUnit.SECONDS)
            .writeTimeout(10, TimeUnit.SECONDS)
            .build()

        Handler().post {
            startNetworkEventByAsyncTask()
        }
    }

    private fun startNetworkEventByAsyncTask() {

        repeat(20) {
            val taskName = "async-task#$it"
            MyTask(taskName).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
        }
    }

    class MyTask(private val taskName: String) : AsyncTask<Void, Void, Void>() {

        private val tag = javaClass.simpleName

        override fun doInBackground(vararg params: Void?): Void? {

            Log.d(tag, "$taskName: start")

            val response = doNetworkTask()
            response.use {
                Log.d(tag, "$taskName: response=" + response.code())
            }

            return null
        }

        override fun onPostExecute(result: Void?) {
            Log.d(tag, "$taskName: done")
        }
    }

    companion object {

        lateinit var client: OkHttpClient

        private fun doNetworkTask(): Response {
            val request = Request.Builder()
                .url("https://自分のサーバ/sleep.php")
                .build()

            return client.newCall(request).execute()
        }
    }
}

実行結果がこちら↓

見事に4スレッドずつ渋滞しながら処理されていきます。

Coroutineの場合

MainActivity.kt
    private fun startNetworkEventByCoroutine() {

        repeat(20) {
            val taskName = "coroutine#$it"
            GlobalScope.launch(Dispatchers.Main) {

                withContext(Dispatchers.IO) {

                    Log.d(tag, "$taskName: start")

                    val response = doNetworkTask()
                    response.use {
                        Log.d(tag, "$taskName: response=" + response.code())
                    }
                }

                Log.d(tag, "$taskName: done")
            }
        }
    }

実行結果がこちら↓

ちょっと分かりにくいですが、ちゃんと20個全部が start に到達し、その後順に response を受けていきます。最初に同時に受け取ったレスポンスが9個しかないのはサーバ側の同時実行数の問題ですね。。

2019-02-20 14:43:09.246 8097-8153/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#0: start
2019-02-20 14:43:09.251 8097-8154/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#1: start
2019-02-20 14:43:09.252 8097-8156/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#2: start
2019-02-20 14:43:09.258 8097-8160/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#5: start
2019-02-20 14:43:09.268 8097-8155/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#6: start
2019-02-20 14:43:09.268 8097-8161/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#7: start
2019-02-20 14:43:09.270 8097-8157/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#3: start
2019-02-20 14:43:09.272 8097-8158/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#4: start
2019-02-20 14:43:09.276 8097-8164/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#9: start
2019-02-20 14:43:09.276 8097-8163/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#8: start
2019-02-20 14:43:09.277 8097-8162/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#10: start
2019-02-20 14:43:09.285 8097-8159/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#11: start
2019-02-20 14:43:09.292 8097-8168/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#13: start
2019-02-20 14:43:09.292 8097-8172/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#12: start
2019-02-20 14:43:09.297 8097-8165/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#15: start
2019-02-20 14:43:09.298 8097-8180/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#16: start
2019-02-20 14:43:09.300 8097-8189/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#19: start
2019-02-20 14:43:09.302 8097-8185/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#18: start
2019-02-20 14:43:09.305 8097-8179/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#17: start
2019-02-20 14:43:09.307 8097-8170/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#14: start
2019-02-20 14:43:11.692 8097-8180/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#16: response=200
2019-02-20 14:43:11.694 8097-8172/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#12: response=200
2019-02-20 14:43:11.694 8097-8168/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#13: response=200
2019-02-20 14:43:11.694 8097-8153/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#0: response=200
2019-02-20 14:43:11.695 8097-8161/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#7: response=200
2019-02-20 14:43:11.695 8097-8162/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#10: response=200
2019-02-20 14:43:11.695 8097-8165/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#15: response=200
2019-02-20 14:43:11.696 8097-8156/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#2: response=200
2019-02-20 14:43:11.696 8097-8154/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#1: response=200
2019-02-20 14:43:11.696 8097-8097/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#7: done
2019-02-20 14:43:11.696 8097-8097/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#10: done
2019-02-20 14:43:11.696 8097-8097/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#16: done
2019-02-20 14:43:11.697 8097-8097/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#15: done
2019-02-20 14:43:11.697 8097-8097/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#2: done
2019-02-20 14:43:11.697 8097-8097/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#0: done
2019-02-20 14:43:11.699 8097-8097/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#12: done
2019-02-20 14:43:11.700 8097-8097/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#13: done
2019-02-20 14:43:11.702 8097-8097/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#1: done
2019-02-20 14:43:12.211 8097-8170/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#14: response=200
2019-02-20 14:43:12.219 8097-8097/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#14: done
2019-02-20 14:43:13.228 8097-8157/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#3: response=200
2019-02-20 14:43:13.235 8097-8097/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#3: done
2019-02-20 14:43:13.240 8097-8160/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#5: response=200
2019-02-20 14:43:13.244 8097-8097/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#5: done
2019-02-20 14:43:14.234 8097-8158/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#4: response=200
2019-02-20 14:43:14.234 8097-8185/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#18: response=200
2019-02-20 14:43:14.246 8097-8097/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#4: done
2019-02-20 14:43:14.247 8097-8097/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#18: done
2019-02-20 14:43:14.248 8097-8155/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#6: response=200
2019-02-20 14:43:14.249 8097-8189/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#19: response=200
2019-02-20 14:43:14.252 8097-8097/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#6: done
2019-02-20 14:43:14.255 8097-8097/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#19: done
2019-02-20 14:43:14.255 8097-8179/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#17: response=200
2019-02-20 14:43:14.256 8097-8097/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#17: done
2019-02-20 14:43:14.414 8097-8164/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#9: response=200
2019-02-20 14:43:14.421 8097-8097/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#9: done
2019-02-20 14:43:15.149 8097-8159/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#11: response=200
2019-02-20 14:43:15.150 8097-8163/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#8: response=200
2019-02-20 14:43:15.154 8097-8097/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#11: done
2019-02-20 14:43:15.155 8097-8097/com.example.coroutinenetworkblockingsample D/MainActivity: coroutine#8: done

まとめ

CoroutineでネットワークI/O待ちになってもちゃんと他のCoroutineが実行される。

AsyncTaskのようなスレッド渋滞は起きない。

当たり前の結果なんだろうけど、Coroutineラクですねぇ。

検証コード一式は https://github.com/takke/CoroutineNetworkBlockingSample に置きました。

追記:単にスレッドがたくさん作られてるだけでした。

例えば100個実行してみると、64個で「渋滞」しました。

16
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
19