skip to Main Content

I’m using PHP 8.2.13 and I’m learning about fiber in php. The code that I’m working on is like this:

<?php
$i = 0;

// Create a fiber that prints even numbers
$fiber1 = new Fiber(function () use (&$fiber2) {
    for ($i=0; $i < 10; $i += 2) {
        echo "Fiber 1: $in";
        // Suspend the fiber and return the next odd number
        Fiber::suspend('fiber1');
        $fiber2->resume($i + 1);
    }
});

// Create a fiber that prints odd numbers
$fiber2 = new Fiber(function ($n) use (&$fiber1) {
    for ($i = $n; $i < 10; $i += 2) {
        echo "Fiber 2: $in";
        // Suspend the fiber and return the next even number
        Fiber::suspend('fiber2');
        $i = $fiber1->resume($i + 1);
    }
});

// Start the first fiber
$fiber1->start();

And the expected output should be like this:

Fiber 1: 0
Fiber 2: 1
Fiber 1: 2
Fiber 2: 3
Fiber 1: 4
Fiber 2: 5
Fiber 1: 6
Fiber 2: 7
Fiber 1: 8
Fiber 2: 9

But unfortunately for me the output is like this:

Fiber 1: 0

I would like help to fix my code, or help me identify my problem.

2

Answers


  1. fibers are not parallel threads, they are just synchronous functions, which means that you cannot build two functions which will resume each other, because of catch 22 – in order to function f1 to be resumed by f2, f1 should suspend itself, but if f1 suspends itself it cannot resume f2

    the best thing you can do is to have 1 primary fiber, which resumes 2nd one:

    // primary fiber, used to print even numbers and resumes 2nd one when needed
    $fiber1 = new Fiber(function () use (&$fiber2) {
        for ($i=0; $i < 10; $i += 2) {
            echo "Fiber 1: $in";
            $fiber2->resume($i+1); // here we pass value to secondary
        };
    });
    
    // secondary fiber, which prints value passed from primary
    $fiber2 = new Fiber(function () use (&$fiber1) {
        do {
            $i = Fiber::suspend(); // here we get value from primary
            echo "Fiber 2: $in";
        } while ($i < 9);
    });
    
    // very important to start fiber2 before fiber1, so primary has something to resume
    $fiber2->start();
    $fiber1->start();
    
    Login or Signup to reply.
  2. If your goal is to execute two fibers alternatively, here is a way to do it:

    $fiber1 = new Fiber(function()
    {
        for($i=0; $i < 10; $i += 2)
            Fiber::suspend($i);
    });
    
    $fiber2 = new Fiber(function()
    {
        for($i=1; $i < 10; $i += 2)
            Fiber::suspend($i);
    });
    
    printf("Fiber 1 returned %dn", $fiber1->start());
    printf("Fiber 2 returned %dn", $fiber2->start());
    
    while(!$fiber1->isTerminated() || !$fiber2->isTerminated())
    {
        if(!$fiber1->isTerminated())
        {
            $val = $fiber1->resume();
            if($val !== null)
                printf("Fiber 1 returned %dn", $val);
        }
    
        if(!$fiber2->isTerminated())
        {
            $val = $fiber2->resume();
            if($val !== null)
                printf("Fiber 2 returned %dn", $val);
        }
    }
    

    Output:

    Fiber 1 returned 0
    Fiber 2 returned 1
    Fiber 1 returned 2
    Fiber 2 returned 3
    Fiber 1 returned 4
    Fiber 2 returned 5
    Fiber 1 returned 6
    Fiber 2 returned 7
    Fiber 1 returned 8
    Fiber 2 returned 9
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search