Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:126596 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 409AF1A00BC for ; Thu, 6 Mar 2025 08:52:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1741250996; bh=1n+RXqjg1DqR8VYlbIV0dlrBeQVcDhc49VwQnum8T/I=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=KtCu+kI415be0sN0zZM0w+gE4UFtAZyid8wvNhP280NwrP5QfgCHfrmUvFqlMuLDP mbw5MQIXWng4ySudXx4Q4p4lBIPcvawLJa+FCTi9MxjJ+NUolLrzAjITzXt/+xYoqM KmbMziK79qYWxrdTmI07MkYCPXTmxa8O6TKh6x3aP1f0hrPE8WRy0FDJZbE53/Pn+4 MXrIBsiEXJ44mMRqeFPb0x1CisHZKCzc5PIQzhhSZKoivgzQ3YfFPK5em++hFpB+C8 116HWPQRMo8/Raub50unL0+Ob1e3thSoqjOVXI/wCWuGPLi/BozJeYsZXtX6JCmpH6 uiM8FbWOTi/eQ== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 5039A18004A for ; Thu, 6 Mar 2025 08:49:55 +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.5 required=5.0 tests=BAYES_05,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-yw1-f179.google.com (mail-yw1-f179.google.com [209.85.128.179]) (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 ; Thu, 6 Mar 2025 08:49:54 +0000 (UTC) Received: by mail-yw1-f179.google.com with SMTP id 00721157ae682-6feb0742878so3773407b3.2 for ; Thu, 06 Mar 2025 00:52:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1741251150; x=1741855950; darn=lists.php.net; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=xQluG+wEqlhbNmgUg67Q5FFIwHab43ZddbQ+HHtGqx8=; b=gKFEnZ2GoSxDkmqHyTvkip6KhE11fda4J9dPtpJ7la1sinG6N0sie2wlw8QhbLCV9a mC3aFsmZ54Cvsi2C83wlG2u3Ac0IRl18hCA8WYy2QBcto1RfkjQva3/C9ror2UjCvx8J 6TPVJZtLdMZBirV+Qn4JQ2KwmRCHK+Pi0jJL3ABRlMk2B7/HQfj1HX26KnTBVZKr5T7G bU28plvPPazIRVrmUqFVwtx5qqQoxVQprdtkEmzvocZdlGyecuMs/J5lbYbpmUfNlCPE zRiTIMf1DxWcqOwsceO/5M14pVazYE62BbmThIN+lYf7071JgjETvgyknwM9om3VykyZ 0YTg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741251150; x=1741855950; h=cc: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=xQluG+wEqlhbNmgUg67Q5FFIwHab43ZddbQ+HHtGqx8=; b=f/CR5Ovk35/EDN/tUDyx3R50NXqQkGhyJ8LB6aebgcPtLEz579kSejEHbSXBH8r6/Y dkKfDMfJRhptUwK8IavXSlVsj/KVqPCVvk856/EFBNdqPkutdrzLIyzK2Qk0Agb2Y8ti IVzCFrFcQJ5qkaI7wQKz8dZLCvf037Wer0nCvitxXSN/j0LKBbg39+7Yh0q6SEYZkXPk QmzNznesbY1gxtfxt2CcHPhP5ykX2FMWeBn6xy16EsJtW6MHX1U/wsxaTGGzdIjbLRHp yUNaZxfV/R9l96b/kJ8RjfF8cctZMfrfyREgFUZ8G8B3qPvvDlfJeQdO8SmEswyoTw02 3TqA== X-Gm-Message-State: AOJu0Yx0aeUZ32zXvlvxY7+denO3XOXl8u50isnY6xxTV8jeYkr7uarC MPOA0So9dTgZ1VW6EY7NvU+tpN/mocOhnxeOhE8C7JWcJQoiY82inV3U8fEHXFnm9HNMkOJpKSz ysFmsgD2UiLGBXqSXCI0X+h+OpUHEb1D5c+ON6g== X-Gm-Gg: ASbGncu5YWRj0dNhx0y5DTUss1HZHbz2u8lvIrtMWlFsBPO9iBRUv38O1zYZjkCgett J2amPDNPBx6UZciaalDX8YlgfWKZFcAPCbEN7plHmtyfGydoiCOauybfVvSJcC6gnD+spKZJy/E ehJiQEdaDITtu01uUCvu+oTzwvWw== X-Google-Smtp-Source: AGHT+IEahhJnANEMHMjNl2WAMnx2pJEKOIns/QBrTRp5H97b47TZ/XniOSTZlvlUkgazwAEVKhHgXmQjIr+P/UkYc14= X-Received: by 2002:a05:690c:4a0a:b0:6fd:63e9:a441 with SMTP id 00721157ae682-6fda30189abmr89588507b3.28.1741251149754; Thu, 06 Mar 2025 00:52:29 -0800 (PST) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 References: <9964db8c-0ffe-43d5-8246-47fc76b07180@app.fastmail.com> <78a03dd0-fd4a-4f4a-ad8a-37e5704f06fc@app.fastmail.com> In-Reply-To: Date: Thu, 6 Mar 2025 10:52:17 +0200 X-Gm-Features: AQ5f1Jr0ZZAHbh_8mpRCtYm3N_-S1j6I3S0uflpOxgKvDE72H58voQYWLh9K8_g Message-ID: Subject: Re: [PHP-DEV] PHP True Async RFC To: Larry Garfield Cc: php internals Content-Type: multipart/alternative; boundary="0000000000003efff5062fa8a02c" From: edmond.ht@gmail.com (Edmond Dantes) --0000000000003efff5062fa8a02c Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable > One key question, if we disallow explicitly creating Fibers inside an async block, > can a Fiber be created outside of it and not block async, or would that also be excluded? Viz, this is illegal: > Creating a `Fiber` outside of an asynchronous block is allowed; this ensures backward compatibility. According to the logic integrity rule, an asynchronous block cannot be created inside a Fiber. This is a correct statement. However, if the asynchronous block blocks execution, then it does not matter whether a Fiber was created or not, because it will not be possible to switch it in any way. So, the answer to your question is: yes, such code is legal, but the Fiber will not be usable for switching. In other words, Fiber and an asynchronous block are mutually exclusive. Only one of them can be used at a time: either Fiber + Revolt or an asynchronous block. Of course, this is not an elegant solution, as it adds one more rule to the language, making it more complex. However, from a legacy perspective, it seems like a minimal scar. (to All: Please leave your opinion if you are reading this ) > // This return statement blocks until foo() and bar() complete. Yes, *that's correct*. That's exactly what I mean. Of course, under the hood, return will execute immediately if the coroutine is not waiting for anything. However, the Scheduler will store its result and pause it until the child coroutines finish their work. In essence, this follows the parent-child coroutine pattern, where they are always linked. The downside is that it requires more code inside the implementation, and some people might accuse us of a paternalistic approach. :) > > should consider if async {} makes sense to have its own catch and finally blocks built in.) > We can use the approach from the RFC to catch exceptions from child coroutines: explicit waiting, which creates a handover point for exceptions= . Alternatively, a separate handler like Context::catch() could be introduced, which can be defined at the beginning of the coroutine. Or both approaches could be supported. There's definitely something to think about here. > > That is still dependency injection, because ThingRunner is still taking all of its dependencies via the constructor. And being readonly, it's still immutable-friendly. > Yeah, so basically, you're creating the service again and again for each coroutine if the coroutine needs to use it. This is a good solution in the context of multitasking, but it loses in terms of performance and memory, as well as complexity and code size, because it requires more factory classes. The main advantage of *LongRunning* is initializing once and using it multiple times. On the other hand, this approach explicitly manages memory, ensuring that all objects are created within the coroutine's context rather than in the global context. Ah, now I see how much you dislike global state! :) However, in a scenario where a web server handles many similar requests, "global state" might not necessarily win in terms of speed but rather due to the simplicity of implementation and the overall maintenance cost of the code. (I know that in programming, there is an entire camp of immutability advocates who preach that their approach is the key remedy for errors.) I would support both paradigms, especially since it doesn=E2=80=99t cost mu= ch. A coroutine will own its internal context anyway, and this context will be carried along with it, even across threads. How to use this context is up to the programmer to decide. But at the same time, I will try to make the pattern you described fit seamlessly into this logic. Ed. --0000000000003efff5062fa8a02c Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
>=C2=A0 One key question, if we disallow explicitly creating Fibers inside an async= block,
> can a Fiber be created outside of it and not block async, = or would that also be excluded?=C2=A0 Viz, this is illegal:
>

C= reating a `Fiber` outside of an asynchronous block is allowed; this ensures= backward compatibility.
According to the logic integrity rule, an async= hronous block cannot be created inside a Fiber. This is a correct statement= .

However, if the asynchronous block blocks execution, then it does n= ot matter whether a Fiber was created or not, because it will not be possib= le to switch it in any way.
So, the answer to your question is: yes, suc= h code is legal, but the Fiber will not be usable for switching.

In o= ther words, Fiber and an asynchronous block are mutually exclusive. Only on= e of them can be used at a time: either Fiber + Revolt or an asynchronous b= lock.

Of course, this is not an elegant solution, as it adds one more= rule to the language, making it more complex. However, from a legacy persp= ective, it seems like a minimal scar.

(to All: Please leave your opin= ion if you are reading this )

>=C2=A0 // This return statement bl= ocks until foo() and bar() complete.

Yes, that's correct. That's exactly what I mean.

Of course, under the hood, = return will execute immediately if the coroutine is not waiting for = anything. However, the Scheduler will store its result and pause it until t= he child coroutines finish their work.

In essence, this follows the p= arent-child coroutine pattern, where they are always linked. The downside i= s that it requires more code inside the implementation, and some people mig= ht accuse us of a paternalistic approach. :)

>=C2=A0
>=C2=A0= should consider if as= ync {} makes sense to have its own catch and finally blocks=C2=A0built in.)
>= =C2=A0
We can use the approach from the RFC to catch exceptions from chi= ld coroutines: explicit waiting, which creates a handover point for excepti= ons.

Alternatively, a separate handler like Context::catch() could be introduced, which can be defined at the beginning of the coro= utine.

Or both approaches could be supported. There's definitely = something to think about here.

>=C2=A0
>=C2=A0 That is still dependency injection, because ThingRunner is still taking all= of its dependencies via the constructor.=C2=A0 And being readonly, it'= s still immutable-friendly.
>=C2=A0

Yeah, so basically, you'= ;re creating the service again and again for each coroutine if the coroutin= e needs to use it. This is a good solution in the context of multitasking, = but it loses in terms of performance and memory, as well as complexity and = code size, because it requires more factory classes.

The main advanta= ge of LongRunning is initializing once and using it multiple times= . On the other hand, this approach explicitly manages memory, ensuring that= all objects are created within the coroutine's context rather than in = the global context.

Ah, now I see how much you dislike global state! = :)

However, in a scenario where a web server handles many similar req= uests, "global state" might not necessarily win in terms of speed= but rather due to the simplicity of implementation and the overall mainten= ance cost of the code. (I know that in programming, there is an entire camp= of immutability advocates who preach that their approach is the key remedy= for errors.)

I would support both paradigms, especially since it doe= sn=E2=80=99t cost much.

A coroutine will own its internal context any= way, and this context will be carried along with it, even across threads. H= ow to use this context is up to the programmer to decide.=C2=A0 But at the same time, I will try to make the pattern you described fit seam= lessly into this logic.

Ed.

--0000000000003efff5062fa8a02c--