Skip to content

Instantly share code, notes, and snippets.

View RaasAhsan's full-sized avatar

Raas Ahsan RaasAhsan

View GitHub Profile

Schedulers

As Cats Effect is a runtime system, it ultimately must deal with the problem of how best to execute the programs which are defined using its concrete implementation (IO). Fibers are an incredibly powerful model, but they don't map 1:1 or even 1:n with any JVM or JavaScript construct, which means that some interpretation is required. The fashion in which this is achieved has a profound impact on the performance and elasticity of programs written using IO.

This is true across both the JVM and JavaScript, and while it seems intuitive that JavaScript scheduling would be a simpler problem (due to its single-threaded nature), there are still some significant subtleties which become relevant in real-world applications.

JVM

IO programs and fibers are ultimately executed on JVM threads, which are themselves mapped directly to kernel threads and, ultimately (when scheduled), to processors. Determining the optimal method of mapping a real-world, concurrent application down to kernel-level thr

Tracing Spec

Tracing is about tracing the structure of an IO computation. Basically, giving some insight into the graph formed by the IO. Tracing is accumulated as the graph is constructed (e.g. by instantiating an IO.Bind node) and reified at the following points:

  • Whenever requested by backtrace: IO[Trace] or printBacktrace: IO[Unit]
  • Whenever an error case is instantiated (IO.Error)

Whenever an exception is rethrown by the interpreter (most commonly in unsafeRunSync()), the associated trace information for that exception should be put into a TracedException wrapper (with cause = the original exception) and that exception should be thrown. This allows backtrace information to participate in side-effectful error recovery and reporting mechanisms. We should consider whether or not we want to also do this with unsafeRunAsync. I'm leaning toward "yes". We should not wrap in TracedException on attempt, raiseError, or any of the other pure error reification mechanisms.

Quick Tips for Fast Code on the JVM

I was talking to a coworker recently about general techniques that almost always form the core of any effort to write very fast, down-to-the-metal hot path code on the JVM, and they pointed out that there really isn't a particularly good place to go for this information. It occurred to me that, really, I had more or less picked up all of it by word of mouth and experience, and there just aren't any good reference sources on the topic. So… here's my word of mouth.

This is by no means a comprehensive gist. It's also important to understand that the techniques that I outline in here are not 100% absolute either. Performance on the JVM is an incredibly complicated subject, and while there are rules that almost always hold true, the "almost" remains very salient. Also, for many or even most applications, there will be other techniques that I'm not mentioning which will have a greater impact. JMH, Java Flight Recorder, and a good profiler are your very best friend! Mea

Thread Pools

Thread pools on the JVM should usually be divided into the following three categories:

  1. CPU-bound
  2. Blocking IO
  3. Non-blocking IO polling

Each of these categories has a different optimal configuration and usage pattern.

@SystemFw
SystemFw / Free conversation.md
Last active October 17, 2023 09:57
Explaining some of the mechanics of interpretation of Free programs

Balaji Sivaraman @balajisivaraman_twitter

Hi all, I need some help understanding a piece of Doobie code from the examples. It is the StreamingCopy one: (https://github.com/tpolecat/doobie/blob/series/0.4.x/yax/example/src/main/scala/example/StreamingCopy.scala). I am using a modified version of the fuseMap2 example from that file. Here’s how I’ve modified it for my requirements:

  def fuseMap[F[_]: Catchable: Monad, A, B](
      source: Process[ConnectionIO, A],
      sink: Vector[A] => ConnectionIO[B],
      delete: ConnectionIO[Unit]
  )(
 sourceXA: Transactor[F],
@raineorshine
raineorshine / testnet-faucet.url
Created June 30, 2016 23:38
Ethereum Morden testnet faucet
http://icarus.parity.io/rain/0xa27528827086ab45b9ce5994aef86cfd39e6a617

Explaining Miles's Magic

Miles Sabin recently opened a pull request fixing the infamous SI-2712. First off, this is remarkable and, if merged, will make everyone's life enormously easier. This is a bug that a lot of people hit often without even realizing it, and they just assume that either they did something wrong or the compiler is broken in some weird way. It is especially common for users of scalaz or cats.

But that's not what I wanted to write about. What I want to write about is the exact semantics of Miles's fix, because it does impose some very specific assumptions about the way that type constructors work, and understanding those assumptions is the key to getting the most of it his fix.

For starters, here is the sort of thing that SI-2712 affects:

def foo[F[_], A](fa: F[A]): String = fa.toString
import React from 'react'
// need a getter and a hash of requestId:results or something
// to use in server rendering
let results = []
function updateTitle() {
document.title = results[results.length - 1]
}
@CMCDragonkai
CMCDragonkai / http_streaming.md
Last active April 25, 2024 17:19
HTTP Streaming (or Chunked vs Store & Forward)

HTTP Streaming (or Chunked vs Store & Forward)

The standard way of understanding the HTTP protocol is via the request reply pattern. Each HTTP transaction consists of a finitely bounded HTTP request and a finitely bounded HTTP response.

However it's also possible for both parts of an HTTP 1.1 transaction to stream their possibly infinitely bounded data. The advantages is that the sender can send data that is beyond the sender's memory limit, and the receiver can act on

Actor Queue Notes

The first thing to understand is that the head field inside of scalaz.concurrent.Actor is not the "head" of the message queue in any traditional sense of the word. A better description would be "last". The there are no pointers to the head of the queue, which one of the very clever things about this implementation.

Empty Actor

Consider the case where the actor has no outstanding messages. This new message will go into the following code:

 def !(a: A): Unit = {