Atomic Counters in Dart

Here’s the translation of the atomic counters example from Go to Dart, with explanations in Markdown format suitable for Hugo:

In Dart, we can use the Isolate class for concurrent programming, which is similar to goroutines in Go. For atomic operations, we’ll use the dart:isolate library’s SendPort and ReceivePort for communication between isolates.

import 'dart:async';
import 'dart:isolate';

void main() async {
  // We'll use a ReceivePort to get the final counter value
  final receivePort = ReceivePort();
  
  // Create 50 isolates that each increment the counter 1000 times
  final futures = List.generate(50, (index) => 
    Isolate.spawn(incrementCounter, receivePort.sendPort));
  
  // Wait for all isolates to complete
  await Future.wait(futures);
  
  // Get the final counter value
  final int ops = await receivePort.first;
  
  print('ops: $ops');
  
  // Close the receive port
  receivePort.close();
}

void incrementCounter(SendPort sendPort) {
  int counter = 0;
  
  for (int i = 0; i < 1000; i++) {
    counter++;
  }
  
  // Send the counter value back to the main isolate
  sendPort.send(counter);
}

In this Dart version:

  1. We use Isolate.spawn to create 50 isolates, each running the incrementCounter function.

  2. Each isolate increments its own local counter 1000 times.

  3. We use a ReceivePort in the main isolate to receive the final counter values from all isolates.

  4. After all isolates complete, we sum up their individual counters to get the total operations count.

  5. The Future.wait is used to wait for all isolates to complete their work, similar to WaitGroup in Go.

To run this program, save it as atomic_counters.dart and use the Dart command:

$ dart run atomic_counters.dart
ops: 50000

We expect to get exactly 50,000 operations. In this Dart implementation, each isolate has its own counter, and we sum them up at the end. This approach avoids the need for atomic operations as each isolate works on its own memory space.

Note that Dart’s isolates are more heavyweight than Go’s goroutines, and they don’t share memory. For simpler concurrency within a single isolate, Dart provides Future and Stream classes, which might be more appropriate for some use cases.

Next, we’ll look at other concurrency patterns in Dart.