Raku actually provides two different locking classes. A Lock object provides a very standard locking mechanism. When .lock and .unlock are used or .protect is called, you get a section of code that pauses until the lock frees up, runs while holding the lock, and then frees the lock so other code that might be waiting on the lock can run.
However, the Lock class works in such a way that blocks the current thread.
What’s more asynchronous than socket communication? When two programs need to talk to each other, often from different computers on different networks in different parts of the world, you can connect using a socket. Whether an HTTP server or some custom protocol, you can implement both sides of that communication using IO::Socket::Async.
Let’s consider a simple calculator service. It listens for connections over TCP. When a connection is established, it takes lines of input over the connection and parses each line as a simple mathematic calculation like 2 + 2 or 6 * 7.
Iteration is slow. If you have N things to process in a loop, your loop will take N iterations to process. Slow. Sometimes that’s the only way, though, to solve a problem.
For example, let’s consider the case where we have a JSON log and we want a command to read each line, parse the JSON for that log, and summarize it showing the time stamp and message:
use JSON::Fast; my $log-file = 'myapp.
The goal of today’s article is to consider when you want to run your tasks simultaneously and how to do that. I am not going to give any rules for this because what works one time may not work the next. Instead, I will focus on sharing some guidelines that I have learned from personal experience.
Remember Your Promises Whenever you use concurrency, you want to hold on to the related Promise objects.
As I have said several times before in this calendar, it is always best to avoid sharing state between running threads. Again, however, here is yet another way to share state, when you need to do it.
A few days ago, we considered monitors as a mechanism for creating a thread-safe object. Let’s consider the following monitor:
class BankBalanceMonitor { has UInt $.balance = 1000; has Lock $!lock .= new; method deposit(UInt:D $amount) { $!
In Raku, a Supply is one of the primary tools for sending messages between threads. From the way a Supply is structured, it is obvious that is provides a means for one ore more tasks to send events to multiple recipient tasks. What is less obvious, however, is that a Supply imposes a cost on the sender.
Consider this program:
my $counter = Supplier.new; start react whenever $counter.Supply { say "A pre-whenever $_"; sleep rand; say "A post-whenever $_"; } start react whenever $counter.
In Raku we have a couple basic ways of getting at the events emitted from a Supply, which begs the question, what’s the difference between each? I want to answer that question by creating a react block with a couple intervals and then emulate the same basic functionality using tap.
Let’s start with our base react block:
sub seconds { state $base = now; now - $base } react { say "REACT 1: {seconds}"; whenever Supply.
A semaphore is a system of sending messages using flags. Oh wait, that’s what a semaphore is outside of computing. Among computers, a semaphore is like a kind of lock that locks after being acquired N times. This is useful for situations where you have a resource of N items, want to quickly distribute them when you know they are available, and then immediately block until a resource has been released.
One challenge I’ve often faced when writing asynchronous code is trying to figure out how to break the problem down in a reasonable way. How far do I go in breaking up my code? How many steps do I want to take? How do I deal with tasks that branch or fork? How do I deal with the interdependencies I’ve created. My hope in this article is to give some guidelines I’ve learned and some tools for answering these questions.
Previously, I discussed the compare-and-swap operation as an operation to perform on atomicint variables. That’s just the tip of the iceberg. While most of the atomic emoji ⚛️ operators are only for atomicints, the cas function, atomic-fetch (or prefix ⚛️ operator), and atomic-assign (or ⚛️= operator) can all be used on any kind of Scalar variable.
First, we need to make sure we know what a Scalar is. In Raku, every variable name is associated with a container.