Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:126629 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by qa.php.net (Postfix) with ESMTPS id DBBD61A00BC for ; Sat, 8 Mar 2025 07:05:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1741417395; bh=IzQflpsbxleq6U4a96PH/i5kJxi5lmMliIALvnYHLtE=; h=References:In-Reply-To:From:Date:Subject:To:From; b=nFRiyrPCDTMvGTbrUtk9gZsv7mxddKeDXSTb6o0cDf4vG9bNH/BhuxBuiFB6SRmSB 9ZFtIizS2ijD00731+T/czR045zUlj5g5mlqn6CWHNgeLo3x1Gk427z8SUc7CjdJj3 GbPEW1i/RMz5LIYg3DyA1QyQLYvahZuM97K9PK4weOeAi9nXtMF7UrgP142hdkhI3M MIOyCDy78p1/pKzZCRJiBEtoT/tnHq5ye7c6IhDz/B+cbu7ulqu1/kcfB4OtE7A/uD 9ZPF2vtr7TMDEK61pT6Ixdp0lYYAx3Q0vFf9KTGv9/bFMoHy1T3aHzFFORE21VK3Cq N42kFHLIk/DTw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 8EC1F18006B for ; Sat, 8 Mar 2025 07:03:14 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_40,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-yb1-f176.google.com (mail-yb1-f176.google.com [209.85.219.176]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Sat, 8 Mar 2025 07:03:14 +0000 (UTC) Received: by mail-yb1-f176.google.com with SMTP id 3f1490d57ef6-e611ebd9a61so2241767276.1 for ; Fri, 07 Mar 2025 23:05:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1741417548; x=1742022348; darn=lists.php.net; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :from:to:cc:subject:date:message-id:reply-to; bh=cFiEHWjnWs4vbrjp5GWL6O3HisxFfgKOhwWAI5EypyQ=; b=ao+iux1hvft+woaOUpMwjQPCMNvIIy/8vQn12m/c5q7Q0xpE0HvNkwOcBfp2tGPq9i noncKo/cOaPGzpJIbI/rSvLvvcMSdoYKgsOYXglJV7wZY8u8wpUvMpw2zDEOpPM06Eq/ DxQb3BGThLnJAOMxOvSfSfv6CvrKnUOiz09lMx875gZ3sloixwIBekgwLhjGgil3kiH6 8thc4Y76rAedP6KAN8LpRn5gC/uKwsLlnRpIUd5drUCnCESGWfa5T5AMCdK7YSEpF+y6 cxgTQyiUIGeeFBVjPuXuS49TkqT9XEiDKjJEABtYUjgOFDX/+TI2+hh/hmGrrI4mGsoI lciQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741417548; x=1742022348; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=cFiEHWjnWs4vbrjp5GWL6O3HisxFfgKOhwWAI5EypyQ=; b=TrEbOQUEg5Ijr+yAsN6o+jAcsE4GyFhZ5dMPQNPl9aOjBUiCvW5FoVCRRI0Mo3g5IZ qXBf1UrabDrCEFAR8Kop8VsHe/EyA8wOZJHjRWaogNxAy1dm9lYweL3g8MN1broXjy8H 5ExaerEtX2XHXrAp+uPcA771BdE//PPQY8namqAqut0x/gAi5pLfrDNeSbGiNQsqvjy4 ZVJySD/tY+JTA46KGfUBtmmS+ahV4iVYvZsarHezFlW1cpIf2NcTAuCavogqeI9epo1Y yd3NUYWQHmmpbQk3umacUb3Klh0rB/RbeVerrZ2oBXtlXEyxUv52fXJu1Mhb8199Fm7X BRuA== X-Gm-Message-State: AOJu0YxIzaXK6wIQFKWlyUY52mj7u8wUY4mx6Xys96m+6HuUuVWWqhnV tZtsbHeZQFjJWXzSx6kkRq9Y5xatOGfXjFoknzpX1lTpvTQ3I65yHEAMxjvceJKeDlJQ7KPDbUL uJZZ8812AfPCOJi/VGyFsCbfBOj8LjaQLksXmYg== X-Gm-Gg: ASbGncthTxkwWqfzA/AQW+fudTMpCVHdg/pSeowUBiVRoLSmkoleGuGKbe4BrW+LVz6 EMsWbcUOLYKzkxmQYjrVNviO+6mTTf+5tA+8kYFa4Jp46LncCDmJZm7HhWn+qovdF2giDIQB8hC Eosf3j3z3TtIP9/gd6/WI1Q4PBsg== X-Google-Smtp-Source: AGHT+IHKJyohyja5Ii7L2xXsI0KeVaE5Fp2SUZPpCFkTdXH/wmswq+62TQE+6eDmQ9G4OSHI2Dt+8vxWue9r/dNFIQ4= X-Received: by 2002:a05:6902:70f:b0:e60:915b:188 with SMTP id 3f1490d57ef6-e636f7e9a04mr2840708276.18.1741417548321; Fri, 07 Mar 2025 23:05:48 -0800 (PST) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 References: In-Reply-To: Date: Sat, 8 Mar 2025 09:05:37 +0200 X-Gm-Features: AQ5f1JqSCVgxSlNqjgfYlPcSNYvhTTUkC7EAVU6KDHvBjAxAiwuPusLZgU7bvLM Message-ID: Subject: [PHP-DEV] Re: PHP True Async RFC To: internals@lists.php.net Content-Type: multipart/alternative; boundary="0000000000005fa2d3062fcf5eea" From: edmond.ht@gmail.com (Edmond Dantes) --0000000000005fa2d3062fcf5eea Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hello all. A few thoughts aloud about the emerging picture. ### Entry point into the asynchronous context Most likely, it should be implemented as a separate function (I haven't come up with a good name yet), with a unique name to ensure its behavior does not overlap with other operators. It has a unique property: it waits for the full completion of the event loop and the Scheduler. Inside the asynchronous context, `Fiber` is prohibited, and conversely, inside a `Fiber`, the asynchronous context is prohibited. ### The `async` operator The `async` (or *spawn*?) operator can be used as a shorthand for spawning a coroutine: ```php function my($param) {} // Operator used as a function call async my(1); or spawn my(1); // Operator used as a closure async { code }; // Since it's a closure, the `use` statement can be used without restrictions async use($var) { code }; // Returns a coroutine class instance $x =3D async use($var) { code }; ``` ### The `await` operator The `await` operator can be added to `async`, allowing explicit suspension of execution to wait for a result: ```php $x =3D await async use($var) { code }; ``` ## Context Manipulations I didn't like functions like `overrideContext`. They allow changing the context multiple times at any point in a function, which can lead to errors that are difficult to debug. This is a really bad approach. It is much better to declare the context at the time of coroutine invocation. With syntax, it might look like this: ```php async in $context use() {} async in $context myFun() async in $context->with("key", value) myFun() or spawn in $context ... ``` ## Thread The syntax spawn in/async in can be used not only in standard cases. ```php $coro =3D async in new ThreadContext() use($channel) { while() {} }; // This expression is also valid $coro =3D async in new $threadPool->borrowContext() use($channel) { while() {} }; ``` It is worth noting that $threadPool itself may be provided by an extension and not be a part of PHP. ## Unrelated Coroutines An additional way is needed to create a coroutine that is not bound to a parent. It's worth considering how to make this as clear and convenient as possible= . Maybe as keyword: ```php async unbound ... ``` Of course, an `async child` modifier can be used. This is the inverse implementation, but I think it will not be used often. Making `unbound` a separate method is not very appealing at the moment because a programmer might forget to call it. They could forget the word `unbound`, and even more so a whole method. ## Context Operations ```php await $context; // Waits for all coroutines in the context $context.cancel(); // Cancels everything within the context ``` ## Flow I want to thank all the participants in the discussion. Thanks to your ideas, questions, and examples. A week ago, answering this question would have been impossible. If we add exception handling and graceful shutdown, and remove the new syntax by replacing it with an equivalent of 2-3 functions, we will get a fairly cohesive RFC that describes the high-level part without unnecessary details. Channels and even Future can be excluded from this RFC =E2=80=94 everything except the coroutine class and context. Microtasks, of course, will remain. As a result, the RFC will be clean and compact, focusing solely on how coroutines and context work. Channels, Future, and iterators can be moved to a separate RFC dedicated specifically to primitives. Finally, after reviewing the high-level RFCs, we can return to the implementation =E2=80=94 in other words, top-down. Given that the approxima= te structure of the lower level is already clear, discussing abstractions will remain practical and grounded. Just to clarify, I=E2=80=99m not planning to end the current discussion the= se are just intermediate thoughts. --- Ed. > --0000000000005fa2d3062fcf5eea Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hello all.

A few= thoughts aloud about the emerging picture.

### Entry point into the= asynchronous context
Most likely, it should be implemented as a separat= e function (I haven't come up with a good name yet), with a unique name= to ensure its behavior does not overlap with other operators. It has a uni= que property: it waits for the full completion of the event loop and the Sc= heduler.=C2=A0

Inside the asynchronous context, `Fiber` is prohibite= d, and conversely, inside a `Fiber`, the asynchronous context is prohibited= .

### The `async` operator
The `async` (or spawn?) operato= r can be used as a shorthand for spawning a coroutine:

```php
fun= ction my($param) {}

// Operator used as a function call
async my(= 1);
or
spawn my(1);

// Operator used as a closure
async {=C2=A0 =C2=A0 code
};

// Since it's a closure, the `use` st= atement can be used without restrictions
async use($var) {
=C2=A0 =C2= =A0 code
};

// Returns a coroutine class instance
$x =3D async= use($var) {
=C2=A0 =C2=A0 code
};
```

### The `await` oper= ator
The `await` operator can be added to `async`, allowing explicit sus= pension of execution to wait for a result:

```php
$x =3D await as= ync use($var) {
=C2=A0 =C2=A0 code
};
```

## Context Manipu= lations
I didn't like functions like `overrideContext`. They allow c= hanging the context multiple times at any point in a function, which can le= ad to errors that are difficult to debug. This is a really bad approach. It= is much better to declare the context at the time of coroutine invocation.= With syntax, it might look like this:

```php
async in $context u= se() {}
async in $context myFun()
async in $context->with("ke= y", value) myFun()
or
spawn in $context ...
```

## Thr= ead
The syntax spawn in/async in can be used not only in st= andard cases.=C2=A0=C2=A0

= ```php
$coro =3D async in new ThreadContext() use($ch= annel) {
=C2=A0 =C2=A0 while() {}
};

// This expression is als= o valid
$coro =3D async in new $threadPool->borrowContext() use($chan= nel) {
=C2=A0 =C2=A0 while() {}
};
```
<= br>It is worth noting that $threadPool itself may be provided = by an extension and not be a part of PHP.=C2=A0=C2=A0

## Unrelated C= oroutines
An additional way is needed to create a coroutine that is not = bound to a parent.
It's worth considering how to make this as clear= and convenient as possible.
Maybe as keyword:
<= div dir=3D"ltr">
```php
async unbound .= ..
```

Of course, an `async child` modifier ca= n be used. This is the inverse implementation, but I think it will not be u= sed often. Making `unbound` a separate method is not very appealing at the = moment because a programmer might forget to call it. They could forget the = word `unbound`, and even more so a whole method.

## Context Operatio= ns
```php
await $context; // Waits for all coroutines in the context<= br>$context.cancel(); // Cancels everything within the context
```

## Flow

I want to thank all the participants in the discussion.Thanks to your ideas, questions, and examples. A week ago, answering this= question would have been impossible.=C2=A0

If we add exception handling and graceful shutdown, and r= emove the new syntax by replacing it with an equivalent of 2-3 functions, w= e will get a fairly cohesive RFC that describes the high-level part without= unnecessary details. Channels and even Future can be excluded= from this RFC =E2=80=94 everything except the coroutine class and context.= Microtasks, of course, will remain.

As a result, the RFC will be clean and compact, focusing solely on how c= oroutines and context work.

Channels, Future, and iterators can be moved to a separate = RFC dedicated specifically to primitives.

Finally, after reviewing the high-level RFCs, we can return to the imple= mentation =E2=80=94 in other words, top-down. Given that the approximate st= ructure of the lower level is already clear, discussing abstractions will r= emain practical and grounded.

Just to clarify, I=E2=80=99m not planni= ng to end the current discussion these are just intermediate thoughts.

---

Ed.

--0000000000005fa2d3062fcf5eea--