Sterling has too many projects Blogging about programming, microcontrollers & electronics, 3D printing, and whatever else...

» Keep Your Thread or Don't

In Raku, there are different ways to pause your code. The simplest and most obvious way to do so is to use sleep:

my $before = now;
sleep 1;
my $after = now - $before;
say $after;

Assuming your system is not bogged down at the moment, the output of $after should be a number pretty close to 1. Not very exciting: you didn’t do anything for a second. Woo. Woo.

In real code, however, you do sometimes need to pause. For example, you might be trying to send an email and it fails. When sending email, it is nice if it arrives quickly, but essential that it arrives eventually. Thus, when queueing up a message, you want to watch for errors. When they occur, you want to keep trying for a long time before giving up. However, you don’t want to keep trying constantly. You need to pause between retries:

» read more

» Parallel Map-Reduce Pattern

Map-reduce is a common way of solving problems in functional programming. You have a list of items, you iterate through them to process them, and then you take the set and summarize them. We call this map-reduce because the iteration step is mapping values to new values and the summarize step reduces the number of values.

In Raku, map-reduce is a common programming pattern:

my $fibonacci = (1, 1, * + * ... *);
my $double-sum = $fibonacci[^100].grep(*.is-prime).map(* * 2).reduce(* + *);

This creates a Seq with the sequence operator. This is the classic Fibonacci sequence. We then take the first 100 elements of Fibonacci, filter out any non-primes, double the primes, and the sum the values.

» read more

» The Divide and Conquer Pattern

Let’s consider now how to solve a big problem with concurrency. If you have an algorithmic problem with lots of data that needs to be processed, you want to maximize the amount of load you can place on the available CPU cores to process it as quickly as possible. To demonstrate how we can go about this in Raku, we will consider Conway’s Game of Life, played on an effectively infinite game board.1

» read more

» Atomic Integers

What’s faster than locks? Compare-and-swap. Modern CPUs have multiple cores. As such, all modern CPUs must have tools for performing absolutely atomic operations to allow those multiple cores to work together. One of those operations is the compare-and-swap or cas operation.

In the abstract, a cas operation takes three arguments, a variable to modify, a given value, and a new value. The variable is set to the new value modified only if the current value held by the variable is equal to the given value. And this is performed as a single operation guaranteed to be safe from interference by any other concurrent operation. Along the way, the system sets a flag marking the success or failure of the operation. If the variable has a different value than expected, the variable is left unchanged and the operation fails. To complete an atomic change, you repeatedly run a calculation and end with a cas operation until it succeeds. That may not sound very efficient, but it turns out that in most cases, it is faster than locks.

» read more

» The Lock Class

When writing concurrent code in Raku, we want to avoid sharing data between tasks. This is because code that shares no data is automatically safe and doesn’t have to worry about interdependencies with other code. So, when you can, you should do your work through Supply, Promise, and Channel objects that are then synchronized together by a central thread. That way, all the state changes are safe.

This is not always practical, though. Sometimes it really is more efficient to share data that can change between tasks running on separate threads. However, such sharing is inherently unsafe.

» read more

» React Blocks

The react block in Raku is the primary means of re-synchronizing asynchronous coding activity. Using it, you can easily pull together promises, supplies, and channels to make a coherent whole of your program or a subsystem.

A react block itself can run any code you want plus one or more whenever blocks. The code in the block will run once and the block will exit either when a done subroutine is called or when all the objects associated with whenever blocks are finished (i.e., all promises are kept or broken, all supplies have quit or closed, and all channels have failed or closed).

» read more

» Raku Schedulers

A large number of concurrency-oriented coding in Raku depends on the use of a Scheduler. Many async operations depend on the default scheduler created by the VM at the start of runtime. You can access this via the dynamic variable named $*SCHEDULER.

The most important feature of a Scheduler is the .cue method. Calling that method with a code reference will schedule the work for execution. The type of scheduler will determine what exactly that means.

» read more

» Threads

Warning! We are delving into the inner depths of Raku now. Threads are a low-level API and should be avoided by almost all applications. However, if your particular application needs direct Thread access, it is here for you.1

Use of the Thread class in Raku is straight-forward and looks very similar to what you would expect if you are familiar with threading tools in other languages:

my $t = Thread.start:
    name => 'Background task',
    :app_lifetime,
    sub {
        if rand > 0.5 { say 'weeble' }
        else { say 'wobble' }
    },
    ;

say "Starting $t.id(): $t.name()";
say "Main App Thread is $*THREAD.id(): $*THREAD.name()";

$t.finish; # wait for the thread to stop

Give the Thread.start method some code to run and you’re off. The name and app_lifetime options are optional. If app_lifetime is False (which is the default), the thread will be terminated when the main application thread terminates. If set to True, the application will continue to run as long as this thread is running. Under normal circumstances, only the main thread of your application has this privilege.

» read more

» Channels

A Channel, in Raku, is an asynchronous queue of data. You can feed data in to one end of the queue and receive data at the other end safely, even when multiple threads are involved.

Let’s consider a variant of the Dining Philosopher Problem: We have five philosophers eating soup at the table. They do not talk to one another because they are too busy thinking about philosophy. However, there are only 2 spoons. Each time a philosopher wishes to take a sip of soup, she needs to acquire a spoon. Fortunately, each philosopher is willing to share spoons and sets her spoon at the center of the table after finishing each bite.

» read more

» Supply Blocks

When you have a stream of data flowing through your Raku application that needs to be accessed safely among threads, you want a Supply. Today we’re going to discuss one particular way of working with supplies, the supply block. If you are familiar with sequences, aka Seq objects, a supply block works in a very similar fashion, but lets you pull work as it arrives and easily do something else in the meantime.

» read more