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
```

Reply via email to