Performance issue with fiber

hanabi1224 harlowmoo at gmail.com
Wed Jul 21 22:51:38 UTC 2021


Hi, I'm new to D lang and encounter some performance issues with 
fiber, not sure if there's something obviously wrong with my code.

Basically, I found D lang's logical thread communication is quite 
like Elixir's (process),
I have programs written in both D and Elixir but the D version 
(release build) is like >5 times slower.

The program is to find first N primes by creating another 
coroutine for every prime found. And the idea is from the 
concurrent prime sieve example on golang's homepage.

Elixir code: 
[1.ex](https://github.com/hanabi1224/Programming-Language-Benchmarks/blob/main/bench/algorithm/coro-prime-sieve/1.ex)

D code: 
[1.d](https://github.com/hanabi1224/Programming-Language-Benchmarks/blob/main/bench/algorithm/coro-prime-sieve/1.d)

Perf result of calculating first 2000 primes on my laptop.

Elixir: 1.33s user 0.25s system 108% cpu 1.451 total

D(dmd): 10.41s user 34.48s system 361% cpu 12.405 total

D(ldc): 8.45s user 33.06s system 356% cpu 11.638 total


Also attaching code inline:

D
```d
import std;
import core.stdc.stdlib: exit;

__gshared Tid mainTid;
__gshared bool terminated = false;

const int mailBoxSize = 1;

void main(string[] args) {
     auto n = args.length > 1 ? args[1].to!int() : 10;
     auto scheduler = new FiberScheduler;
     scheduler.start({
         mainTid = thisTid();
         setMaxMailboxSize(mainTid, n, OnCrowding.throwException);
         auto filterTid = spawnLinked(&filter, n);
         setMaxMailboxSize(filterTid, mailBoxSize, 
OnCrowding.block);
         auto generatorTid = spawnLinked(&generate, filterTid);
         for(auto i=0;i<n;i++){
             auto prime = receiveOnly!int;
             writeln(prime);
         }
         terminated = true;
         exit(0);
     });
}

void generate(Tid tid) {
     for (auto i=2;!terminated;i++) {
         tid.send(i);
     }
}

void filter(int nLeft) {
     auto prime = receiveOnly!int;
     mainTid.send(prime);
     if (nLeft > 0) {
         filterInner(prime, nLeft);
     }
}

void filterInner(int prime, int nLeft) {
     auto nextTid = spawnLinked(&filter, nLeft-1);
     setMaxMailboxSize(nextTid, mailBoxSize, OnCrowding.block);
     while(!terminated){
         auto d = receiveOnly!int;
         if (d % prime != 0) {
             nextTid.send(d);
         }
     }
}
```
Elixir
```elixir
defmodule App do
   def main(args) do
     n = String.to_integer(Enum.at(args,0,"27"), 10)
     generate(n)
   end

   def generate(n) do
     mainPid = self()
     pid = spawn_link(fn -> filter(mainPid, n) end)
     generateLoop(pid, 2)
   end

   def generateLoop(pid, n) do
     send(pid, {:n, n})
     receive do
       :gen -> generateLoop(pid, n + 1)
     end
   end

   def filter(mainPid, nLeft) do
     receive do
       {:n, n} -> filterInner(mainPid, n, nLeft)
     end
   end

   def filterInner(mainPid, prime, nLeft) do
     send(mainPid, :gen)
     IO.puts("#{prime}")
     if nLeft > 1 do
       pid = spawn_link(fn -> filter(mainPid, nLeft-1) end)
       recieveAndSendToFilter(mainPid, self(), pid, prime)
     else
       System.halt(0)
     end
   end

   def recieveAndSendToFilter(mainPid, rxPid, txPid, prime) do
     receive do
       {:n, n} -> recieveAndSendToFilterInner(mainPid, rxPid, 
txPid, prime, n)
     end
   end
   def recieveAndSendToFilterInner(mainPid, rxPid, txPid, prime, 
n) do
     if Integer.mod(n, prime) != 0 do
       send(txPid, {:n, n})
     else
       send(mainPid, :gen)
     end
     recieveAndSendToFilter(mainPid, rxPid, txPid, prime)
   end
end
```


More information about the Digitalmars-d-learn mailing list