[ 
https://issues.apache.org/jira/browse/GROOVY-12459?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18128409#comment-18128409
 ] 

ASF GitHub Bot commented on GROOVY-12459:
-----------------------------------------

github-actions[bot] commented on PR #2987:
URL: https://github.com/apache/groovy/pull/2987#issuecomment-6249889929

   ### JMH summary — indy (commit `23edbfe`)
   
   Speedup vs trailing 90-day baseline on gh-pages. Higher = faster.
   `1.00` = in line with history. Per-benchmark ratio, geomean within group.
   Time-per-op units inverted so direction is consistent. The *calibrated*
   column divides out this runner's speed vs the baseline hardware, as
   measured by Groovy-independent pure-Java ruler benchmarks.
   
   | Group  | Speedup | Calibrated | n |
   |--------|---------|------------|---|
   | bench | 0.970 × | 1.070 × | 124 |
   | core | 2.271 × | 2.298 × | 108 |
   | grails | 1.342 × | 1.413 × | 80 |
   
   No benchmark is ≥1.5× slower than its 90-day baseline.
   
   <sub>Runner calibration (this run vs baseline hardware): bench 0.92× (27 
rulers) · core-ag 0.96× (3 rulers) · core-hz 1.03× (3 rulers) · grails-ad 0.97× 
(3 rulers) · grails-ez 0.94× (3 rulers)</sub>
   
   <sub>Baseline: <code>dev/bench/jmh/&lt;part&gt;/indy/data.js</code> on 
gh-pages, trailing 90 days. <a 
href="https://apache.github.io/groovy/dev/bench/jmh/summary.html";>Daily 
dashboard</a> · <a 
href="https://apache.github.io/groovy/dev/bench/jmh/";>Per-suite raw 
data</a></sub>
   
   <!

> Failed AsyncChannel producer never closes the channel so `for await` hangs 
> and the exception is dropped
> -------------------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12459
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12459
>             Project: Groovy
>          Issue Type: Bug
>            Reporter: Daniel Sun
>            Priority: Major
>
> h2. Context
> {{AsyncChannel}} is the channel used with {{async}} and {{for await}}. A 
> producer often sends a few values and then calls {{close()}} so the consumer 
> can finish. That shape shipped with the channel API. Native async/await is 
> GROOVY-9381. Later channel work includes GROOVY-12320 ({{ChannelSelect}}) and 
> GROOVY-12343 ({{AsyncChannel.after}}).
> The proposed change teaches the channel to carry a producer failure on the 
> same close signal the rest of the API already understands.
> h2. Problem
> {code:groovy}
> def channel = AsyncChannel.create(2)
> async {
>     for (int i = 1; i <= 3; i++) {
>         someCall()
>         channel.send(i * i)
>     }
>     channel.close()
> }
> for await (value in channel) {
>     println value
> }
> {code}
> If {{someCall()}} throws, both of these happen:
> * {{channel.close()}} never runs, so {{for await}} waits forever.
> * The exception stays on the {{Awaitable}} returned by {{async}}. The example 
> discards that handle, so nothing in the consuming code sees the failure.
> A {{try}} / {{finally}} inside the task, followed by {{await}} on the handle, 
> fixes both symptoms, but the consumer is waiting on the channel, not on the 
> handle. A resource that exists only inside the task does not have this 
> problem: {{defer}} already runs on the way out, and {{await}} on the handle 
> reports the exception.
> h2. Change
> {{receive}} and {{send}} still end with {{ChannelClosedException}}. A 
> retained failure is that exception's cause, not a second exception type. 
> Buffered values are delivered first. The first close wins; a later close does 
> not replace it.
> ||What happened||What the consumer sees||
> |{{close()}}, or {{close(null)}}|{{ChannelClosedException}} with no cause. 
> {{for await}} ends. {{ChannelSelect}} still treats this as a normal close.|
> |{{close(failure)}} when the channel retains it|{{ChannelClosedException}} 
> whose cause is {{failure}}. {{for await}} and {{ChannelSelect}} throw 
> {{failure}} after values already sent.|
> |A withdrawn {{ChannelSelect}} branch|Unchanged. It is not a close, so it 
> stays silent.|
> {{produce}} is the helper for the example above. It runs the body and then 
> closes the channel. On success the body just returns. On failure it calls 
> {{close(failure)}}.
> * When that call returns {{true}}, receivers observe the failure and the 
> returned {{Awaitable}} completes with {{null}}.
> * When it returns {{false}}, the channel is still closed, so the consumer 
> does not hang, and the {{Awaitable}} completes with the body exception.
> {code:groovy}
> def channel = AsyncChannel.create(2)
> channel.produce { out ->
>     for (int i = 1; i <= 3; i++) {
>         someCall()
>         out.send(i * i)
>     }
> }
> for await (value in channel) {
>     println value
> }
> {code}
> {{filter}}, {{map}}, {{merge}}, {{split}}, and {{tap}} keep a normal upstream 
> close as a normal close. An upstream failure is passed on with the same 
> cause, so a later {{for await}} still sees it.
> {{getCloseCause()}} only reports a failure the channel actually retained. The 
> default is {{null}}.
> h2. Compatibility
> The new methods are default methods, added after the 6.0.0 channel API, so a 
> class compiled against that API does not need to be recompiled and does not 
> throw {{AbstractMethodError}}.
> * {{close(null)}} delegates to {{close()}}. The return value still means this 
> call closed the channel.
> * {{close(failure)}} on that older class calls {{close()}} and returns 
> {{false}}. The failure is not stored. {{produce}} then completes its 
> {{Awaitable}} with the body exception.
> * {{DefaultAsyncChannel}} stores the cause under the same lock as the closed 
> flag and returns {{true}} only when receivers will observe it. {{close()}} 
> and {{close(Throwable)}} both enter one private close, so neither calls the 
> other.
> A resource that lives only inside an {{async}} task is unchanged: release it 
> with {{defer}}, and observe the task with {{await}} or with {{scope.async}} 
> inside {{AsyncScope.withScope}}.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to