Sling Academy
Home/Kotlin/Difference Between `launch` and `async` in Kotlin

Difference Between `launch` and `async` in Kotlin

Last updated: December 01, 2024

The Kotlin programming language provides a powerful set of tools for handling concurrency. Two commonly used mechanisms are launch and async. Though both are integral to dealing with coroutine-based concurrent execution, they serve different purposes.

Understanding coroutines in Kotlin

Before diving into launch and async, it's essential to understand what a coroutine is. In Kotlin, a coroutine is a design pattern used to simplify asynchronous code by executing in a single-threaded manner. They enable concurrent execution without needing to manage complex thread logic directly.

The launch Coroutine Builder

The launch function is a coroutine builder that starts a new coroutine without blocking the current thread and returns a Job. It is primarily used when you don’t care about the result from the lambda expression passed to it. Thus, it's mostly suitable for fire-and-forget tasks. For example:


import kotlinx.coroutines.*

fun main() = runBlocking {
    val job = launch {
        // long running operation
        delay(1000L)
        println("Launch: Task complete!")
    }
    println("Inside runBlocking")
    job.join() // waits for the coroutine to finish
    println("RunBlocking complete!")
}

In the above code, launch creates a new coroutine in a non-blocking fashion and outputs the result once the delay is over.

The async Coroutine Builder

The async builder is also nondisruptive to the current thread, but it returns a Deferred object, which can store a result from the coroutine. You can retrieve the result using the await function. Here's an illustrative example:


import kotlinx.coroutines.*

fun main() = runBlocking {
    val result = async {
        delay(1000L)
        println("Async: Task complete!")
        "Finished"
    }
    println("Inside runBlocking")
    println("Deferred Result: ${result.await()}")
    println("RunBlocking complete!")
}

In this example, the coroutine started by async provides a result that can be awaited, showcasing how it’s more appropriate when a return value is desired from concurrent execution.

Choosing between launch and async

Choosing between launch and async depends on whether you need the result of parallel execution. Use launch for routines where you don't require any result and async when you do. A key point to consider: if there's a brought forward computational representation, always prefer async. Conversely, opt for launch when acknowledging or performing background operations.

Example Comparison

Here's an example demonstrating both launch and async exhibiting similar functionality while differing outcomes regarding result utilization:


import kotlinx.coroutines.*

fun main() = runBlocking {
    val launchResult = launch {
        delay(200L)
        println("Launch coroutine finished")
    }

    val asyncResult = async {
        delay(500L)
        "Async coroutine finished"
    }

    println("Before awaiting")
    launchResult.join()  // As launch doesn't return a result
    println(asyncResult.await())  // Await returns a result from async
    println("End of runBlocking")
}

In this situation, launch runs independently with the primary thread block until it finished without needing result feedback. Meanwhile, async returns a string that is 'awaited' and then printed, proving its ability to offer a combination of non-blocking results amid concurrent workloads.

Conclusion

In practice, understanding the specificity of launch and async in Kotlin provides the means for efficiently managing non-blocked concurrency with coroutines. They each serve distinct roles, contributive to proficient sporadic operations leveraging optimal execution in controlled locality, allowing developers to strategize concurrency usage. Whether handling fire-and-forget work scenarios or returning computational results, selecting the appropriate coroutine builder is crucial in constructing smooth, readable concurrent programs.

Next Article: How to Handle Asynchronous Tasks with Coroutines in Kotlin

Previous Article: Understanding `async` and `await` in Kotlin Coroutines

Series: Kotlin - Coroutines and Asynchronous Programming

Kotlin

You May Also Like

  • How to Use Modulo for Cyclic Arithmetic in Kotlin
  • Kotlin: Infinite Loop Detected in Code
  • Fixing Kotlin Error: Index Out of Bounds in List Access
  • Setting Up JDBC in a Kotlin Application
  • Creating a File Explorer App with Kotlin
  • How to Work with APIs in Kotlin
  • What is the `when` Expression in Kotlin?
  • Writing a Script to Rename Multiple Files Programmatically in Kotlin
  • Using Safe Calls (`?.`) to Avoid NullPointerExceptions in Kotlin
  • Chaining Safe Calls for Complex Operations in Kotlin
  • Using the Elvis Operator for Default Values in Kotlin
  • Combining Safe Calls and the Elvis Operator in Kotlin
  • When to Avoid the Null Assertion Operator (`!!`) in Kotlin
  • How to Check for Null Values with `if` Statements in Kotlin
  • Using `let` with Nullable Variables for Scoped Operations in Kotlin
  • Kotlin: How to Handle Nulls in Function Parameters
  • Returning Nullable Values from Functions in Kotlin
  • Safely Accessing Properties of Nullable Objects in Kotlin
  • How to Use `is` for Nullable Type Checking in Kotlin