Hello! I've been trying to understand how threadi...
# ktor
a
Hello! I've been trying to understand how threading and coroutines work in Ktor. I noticed this:
Copy code
get {
    Thread.currentThread().name // eventLoopGroupProxy-4-1
    coroutineContext[ContinuationInterceptor] // NettyDispatcher@444e12d2

    launch(Dispatchers.Default) {
        Thread.currentThread().name // DefaultDispatcher-worker-1
        coroutineContext[ContinuationInterceptor] // Dispatchers.Default

        withContext(Dispatchers.IO) {
            Thread.currentThread().name // DefaultDispatcher-worker-1
            coroutineContext[ContinuationInterceptor] // Dispatchers.IO
        }
    }
}
• I am assuming well if I say that Default dispatcher and IO dispatcher works both on the same type of thread? • The Default dispatcher is either a dispatcher as such or it is one of the other dispatchers configured to be the default dispatcher?
1
s
It's great to do your own research before asking questions, but as I think you've discovered, asking ChatGPT is not research. You've no way of knowing if it's wrong or right, and I don't think you'll find many people interested in poring over its fairly arbitrary outputs to check it for correctness. We can certainly help point to real sources of information and answer specific questions, though! Is there anything specific that you're uncertain about in the code and info you shared after comparing it with the official documentation?
💯 2
a
I've researched this topic a few times, pointing out things that aren't on internet (at least in the first 5 pages): https://kotlinlang.slack.com/archives/C0A974TJ9/p1710005378464099 Also I discussed the topic with other people in this channel. Probably the questions is not the best or is not well written but if you don't want to answer you can just ignore it.
s
If you want to assist people who want to ignore it it'd be much better to provide a succinct question in the main channel and then copy paste the ChatGPT wall of text inside the thread. Here's a random example I found https://kotlinlang.slack.com/archives/CJLTWPH7S/p1680170260342599?thread_ts=1680170260.342599&cid=CJLTWPH7S of someone doing exactly that and not cluttering the main channel for those who aren't interested in the original question.
a
True @Stylianos Gakis , thanks
👍 1
Let's see if ChatGPT has accurate with the info:
Copy code
get {
    Thread.currentThread().name // eventLoopGroupProxy-4-1
    coroutineContext[ContinuationInterceptor] // NettyDispatcher@444e12d2

    launch(Dispatchers.Default) {
        Thread.currentThread().name // DefaultDispatcher-worker-1
        coroutineContext[ContinuationInterceptor] // Dispatchers.Default

        withContext(Dispatchers.IO) {
            Thread.currentThread().name // DefaultDispatcher-worker-1
            coroutineContext[ContinuationInterceptor] // Dispatchers.IO
        }
    }
}
NettyDispatcherUsage: Specific to Ktor when using Netty as the server. • Purpose: Handles non-blocking I/O operations for network connections. • Characteristics: ◦ Optimized for network and asynchronous I/O operations. ◦ Utilizes Netty's EventLoopGroup threads, which are lightweight and manage multiple connections efficiently. • Example Use: Processing incoming HTTP requests without blocking. Dispatchers.Default • Usage: General purpose in Kotlin coroutines for CPU-intensive operations. • Purpose: Execute tasks that require heavy CPU usage, such as complex computations or data processing. • Characteristics: ◦ Uses a thread pool that adjusts according to the system's load and available CPUs. ◦ Suitable for non-blocking CPU-consuming tasks. • Example Use: Data processing algorithms, mathematical computations. Dispatchers.IO • Usage: General purpose in Kotlin coroutines for blocking I/O operations. • Purpose: Handle I/O tasks that may block, such as database accesses, file reading/writing, synchronous network calls. • Characteristics: ◦ Optimized for blocking I/O operations. ◦ Uses a larger thread pool than
Dispatchers.Default
to handle the blocking nature of I/O tasks. • Example Use: Database queries, file system access, synchronous network calls. Is this correct for you?
Edited to add some questions
Copy code
routing {
  get("/default") {
    queryDatabase()
      call.respond(HttpStatusCode.OK)
  }
  get("/io") {
    withContext(Dispatchers.IO) {
      queryDatabase()
      call.respond(HttpStatusCode.OK)
    }
  }
}

fun queryDatabase(): String {
    // Simulate a blocking I/O operation
    Thread.sleep(2000) // This blocks the current thread
    return "Database query result"
}
I run this against K6 to test performance and then I ask GPT to summarize the results, so interesting:
Copy code
Execution 1 to /default using event loop thread and netty dispatcher:

Metrics:
    Status: 100% (240 requests, all successful)
    Data Received: 9.1 kB (185 B/s)
    Data Sent: 22 kB (453 B/s)
    HTTP Requests Blocked: Avg 1.72ms
    HTTP Requests Duration: Avg 15.76s
    HTTP Requests Waiting: Avg 15.76s
    HTTP Requests Receiving: Avg 35.14µs
    HTTP Requests Sending: Avg 12.14µs
    Iterations: 240 (4.87/s)
    Virtual Users (VUs): 10 initially, max 100

Observations:
    Request Duration: Very high average duration of 15.76 seconds.
    Iterations: Completed 240 iterations.
    VUs: Peaked at 100 VUs.
    Overall Performance: Poor, indicating significant blocking or high latency.
Copy code
Execution 2 to /io using worker thread and IO dispatcher:

Metrics:
    Status: 100% (968 requests, all successful)
    Data Received: 37 kB (1.1 kB/s)
    Data Sent: 85 kB (2.6 kB/s)
    HTTP Requests Blocked: Avg 392.96µs
    HTTP Requests Duration: Avg 2.22s
    HTTP Requests Waiting: Avg 2.22s
    HTTP Requests Receiving: Avg 23.83µs
    HTTP Requests Sending: Avg 24.94µs
    Iterations: 968 (29.29/s)
    Virtual Users (VUs): 8 initially, max 100

Observations:
    Request Duration: Significantly lower average duration of 2.22 seconds.
    Iterations: Completed 968 iterations.
    VUs: Peaked at 100 VUs.
    Overall Performance: Much better, indicating lower blocking and improved handling of requests.