swoole / swoole-src

🚀 Coroutine-based concurrency library for PHP
https://www.swoole.com
Apache License 2.0
18.47k stars 3.16k forks source link

Co:getContext() is returning empty array for all different coroutine contexts #4839

Closed fakharak closed 2 years ago

fakharak commented 2 years ago

Please answer these questions before submitting your issue.

  1. What did you do? If possible, provide a simple script for reproducing the error.

I ran the script below to test the output of Co::getcontext() function.

use Swoole\Coroutine as Co;

$run = new Swoole\Coroutine\Scheduler;

// Context 1
$run->add(function()
{
    Co::sleep(1);
    echo "Context 1 is done.\n";
   print_r(Co::getContext());
});

// Context 2
$run->add(function()
{
    Co::sleep(1);
    echo "Context 2 is done.\n";
    print_r(Co::getContext());
});

// Context 3
$run->add(function()
{
    echo "Context 3 is done.\n";
    print_r(Co::getContext());
});

// Required or context containers won't run
$run->start();
  1. What did you expect to see?

Different contexts arrays.

  1. What did you see instead?

Exactly same Context with empty array as below, for all those three different Contexts:

Swoole\Coroutine\Context Object
(
    [storage:ArrayObject:private] => Array
        (
        )

)
  1. What version of Swoole are you using (show your php --ri swoole)?

OpenSwoole 4.11.1

  1. What is your machine environment used (show your uname -a & php -v & gcc -v) ?

Linux fakhar-HP-Laptop 5.17.5-76051705-generic #202204271406~1651504840~20.04~63e51bd-Ubuntu SMP PREEMPT Wed Ma x86_64 x86_64 x86_64 GNU/Linux

8.1.10

11.2.0

NathanFreeman commented 2 years ago

Every coroutine has their own stack, Context object look the same, but actually different. You can use below code to test it.

<?php
use Swoole\Coroutine as Co;

$run = new Swoole\Coroutine\Scheduler;

// Context 1
$run->add(function()
{
    $context = Co::getContext();
    $context['Context1'] = 'Context 1';
    Co::sleep(1);
    echo "Context 1 is done.\n";
    echo $context['Context1'].PHP_EOL;
});

// Context 2
$run->add(function()
{
    $context = Co::getContext();
    $context['Context2'] = 'Context 2';
    Co::sleep(2);
    echo "Context 2 is done.\n";
    echo $context['Context2'].PHP_EOL;
});

// Context 3
$run->add(function()
{
    echo "Context 3 is done.\n";
    $context = Co::getContext();
    $context['Context3'] = 'Context 3';
    echo $context['Context3'].PHP_EOL;
});

// Required or context containers won't run
$run->start();
fakharak commented 2 years ago

@NathanFreeman Ahh okay so the function returns an object representing an empty Stack (object with empty array), which is internally uniquely identified (behind the scene) by Swoole engine itself for each Context (of a set of coroutine/s).

I misinterpreted the official documentation as if it returns an object with array containing single value which is an id of the Context. It would be good if that fact (returned Data Structure) is elaborated (explained) in more detail.

As a reference to document, i was reading the Context Manager concept / code on this link: Isolating Global Variables When Coroutine Enabled

Thank you.

fakharak commented 2 years ago

@NathanFreeman Just one more clarity:

Is there one context created per "Co\run ()" ? OR, there is a context created for each coroutine (per go() function) ?

In other words, If there are more then one go() calls inside a Co\run(), then will all go() functions share same context (same as that of "Co\run() inside which they live) ? CoroutineContext

My assumption is that there is one context created per Co\run() and all go() functoins inside that Co\run() share same context. Please, correct me if i am wrong. Reference (Please, see the highlighted paragraph in attached screen): https://openswoole.com/article/isolating-variables-with-coroutine-context

NathanFreeman commented 2 years ago

Co\run() and all go() functoins have their own context and each coroutine can not share context each other unless use channel or global variable.

Co\run() just perform the initialization work and generate main coroutine.

fakharak commented 2 years ago

So, the call to all of these below;

  1. Co\run(),
  2. $scheduler->add(), and go() create a Coroutine Context.

The context of a nested go() is separate from the Context of parent go().

Please, reflect this very important fact about nested co-routines, repetitively, everywhere in the official Swoole Documentation, specially where following is discussed:

  1. Coroutines,
  2. Swoole Server Request / Recieve
  3. Coroutine Scheduler,
  4. Co\run,
  5. Context Manager
deminy commented 2 years ago

@fakharak Please check the comments from project swoole/ide-helper:

These should help answer some of your questions. Also, To better answer questions, I'm thinking of adding some new examples in my personal project deminy/swoole-by-examples, probably within next two weeks.

Please feel free to let us know any other questions.

deminy commented 2 years ago

Added a new example about using Context objects in coroutines.