Synchronous and Asynchronous Fibers in ZIO

Visualizing data - abstract purple background with motion blur, digital data analysis concept
Reading Time: 2 minutes

In this blog post, we will discuss operations on fiber both synchronous and asynchronous with the help of an example.

fibers

ZIO

ZIO is a highly concurrent framework, powered by fibers, which are lightweight virtual threads that achieve massive scalability compared to threads, augmented with resource-safe cancellation, which powers many features in ZIO.

However, this powerful concurrency model lets you do more with less, achieving highly scalable, ultra-low-latency applications that are globally efficient and resource-safe.

ZIO is a next-generation framework for building cloud-native applications on the JVM, with a beginner-friendly yet powerful functional core.

ZIO library is purely functional and showcases the power of pure functional programming to solve modern business problems.

Fibers

Fiber are lightweight equivalents of operating system threads. Similarly like a thread, a fiber models a running computation and instructions on a single fiber are executed sequentially.

However, fiber are much less costly to create than operating system threads, so we can have hundreds of thousands of fibers in our program at any given time whereas maintaining this number of threads would have a severe performance impact. Unlike threads, fiber are also safely interruptible and can be joined without blocking.

Synchronous Fibers

Here tasks are executed synchronously means one by one by a single fiber zio-default-async-1. Once a task is completed then only the execution of the new task will start on the same thread.

override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = synchronousRoutine().exitCode

val task1: UIO[String] = ZIO.succeed("Task-1")
val task2: UIO[String] = ZIO.succeed("Task-2")
val task3: UIO[String] = ZIO.succeed("Task-3")

def printThread = s"[${Thread.currentThread().getName}]"

def synchronousRoutine() = for {
  _ <- task1.debug(printThread)
  _ <- task2.debug(printThread)
  _ <- task3.debug(printThread)
} yield ()
/**
 * Output:
 * [zio-default-async-1]: Task-1
 * [zio-default-async-1]: Task-2
 * [zio-default-async-1]: Task-3
 */

Asynchronous Fibers

Here tasks are executing asynchronously means many at one time on different fibers:
zio-default-async-3, zio-default-async-4, zio-default-async-2 using fork method

override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = aSynchronousRoutine().exitCode

val task1: UIO[String] = ZIO.succeed("Task-1")
val task2: UIO[String] = ZIO.succeed("Task-2")
val task3: UIO[String] = ZIO.succeed("Task-3")

def printThread = s"[${Thread.currentThread().getName}]"

def aSynchronousRoutine() = for {
  _ <- task1.debug(printThread).fork
  _ <- task2.debug(printThread).fork
  _ <- task3.debug(printThread).fork
} yield ()
/**
 * Output:
 * [zio-default-async-3]: Task-2
 * [zio-default-async-4]: Task-3
 * [zio-default-async-2]: Task-1
 * If you run this code, The output might not be exactly same as it is working asynchronously
 */

Conclusion

In this blog, we discussed ZIO and ZIO fibers. We also took a brief about synchronous and asynchronous fibers in ZIO. To read more blogs like this, do check out here

You can also read about the basic Introduction to ZIO Fiber and fiber data type here

For exploring more regarding ZIO Fiber please refer to the following link

https://zio.dev/overview/overview_basic_concurrency

Written by 

Pragati is currently working as a Software Engineer at Knoldus Inc. She is having more than 1.5 year of experience working in IT industry and working in the Scala domain.

Discover more from Knoldus Blogs

Subscribe now to keep reading and get access to the full archive.

Continue reading