<div dir="auto"><div>> The problem is that unlike any other classes in java.util.concurrent, STS is not thread safe by default, it requires to carefully implement any subclasses in a thread safe way.</div><div dir="auto"><br></div><div dir="auto">Yes, it is true, this is a result of the fact that structured concurrency is designed to be similar, and to be easily integrated, with a imperative style programming.</div><div dir="auto"><br></div><div dir="auto">> the implementation provided by Holo may not work because [...]</div><div dir="auto"><br></div><div dir="auto">All of those are of course true, to make it production ready you would need to add locks, the moment you add locks you can also solve the O(n) problem.</div><div dir="auto"><br></div><div dir="auto">> I would prefer to provide an API easier to use</div><div dir="auto"><br></div><div dir="auto">Again, this is true. I would like to have as part of the default implementations an implementation of STS that have a good Short-circuit strategy as a parameter (and a Transformer is a nice to have as well)</div><div dir="auto"><br></div><div dir="auto">> I believe that having a method join() that takes a function that takes a stream is easier to use correctly</div><div dir="auto"><br></div><div dir="auto">This is the first place I disagree with you. Before explaining more why I disagree I need to point out, implementing a STS that have a `await(Stream -> T) -> T method that works as you described is possible, and it is in fact *extremely* similar to the example I have (±locks I omitted and data structures), you can make it and use it everywhere (I'm aware that there are nuances here, but I believe you can overcome them).</div><div dir="auto"><br></div><div dir="auto">Now, I *strongly* against putting such implementation in the j.u.concurrency, the API you described encourages a paradigm that is not what the API is aiming for, what you really want to write is not </div><div dir="auto"><br></div><div dir="auto">T result;</div><div dir="auto">try (var scope = ...) { \\ 0</div><div dir="auto"> scope.fork(...); \\1</div><div dir="auto"> for (...) { \\ 2</div><div dir="auto"> scope.fork(...); \\ 3</div><div dir="auto"> }</div><div dir="auto"> result = scope.await(out -> out.flatMap(...)); \\4</div><div dir="auto">}</div><div dir="auto"><br></div><div dir="auto">But rather:</div><div dir="auto">T result = </div><div dir="auto"> new StructuredTaskStream(...) \\ 0</div><div dir="auto"> .fork(...) \\ 1</div><div dir="auto"> .takeWhile(...) \\ 2</div><div dir="auto"> .fork(...) \\ 3</div><div dir="auto"> .flatMap(...); \\ 4</div><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto">Which is a different paradigm, and indeed a different implementation of structures concurrency **as long as** you guarantee that after the scope of any terminating operator all of the tasks ended, successfully or otherwise.</div><div dir="auto"><br></div><div dir="auto">Such API can work, and I know people who prefer that style, but this doesn't change the fact that the STScope is not designed for this paradigm</div><div dir="auto"><br><div class="gmail_quote" dir="auto"><div dir="ltr" class="gmail_attr">On Wed, May 10, 2023, 18:01 <<a href="mailto:forax@univ-mlv.fr" target="_blank" rel="noreferrer">forax@univ-mlv.fr</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">----- Original Message -----<br>
> From: "Alan Bateman" <<a href="mailto:Alan.Bateman@oracle.com" rel="noreferrer noreferrer" target="_blank">Alan.Bateman@oracle.com</a>><br>
> To: "Holo The Sage Wolf" <<a href="mailto:holo3146@gmail.com" rel="noreferrer noreferrer" target="_blank">holo3146@gmail.com</a>>, "Remi Forax" <<a href="mailto:forax@univ-mlv.fr" rel="noreferrer noreferrer" target="_blank">forax@univ-mlv.fr</a>><br>
> Cc: "Ron Pressler" <<a href="mailto:ron.pressler@oracle.com" rel="noreferrer noreferrer" target="_blank">ron.pressler@oracle.com</a>>, "loom-dev" <<a href="mailto:loom-dev@openjdk.java.net" rel="noreferrer noreferrer" target="_blank">loom-dev@openjdk.java.net</a>><br>
> Sent: Wednesday, May 10, 2023 3:03:11 PM<br>
> Subject: Re: Structured Concurrency yet again<br>
<br>
> On 10/05/2023 07:47, Holo The Sage Wolf wrote:<br>
>> The way to handle these cases is to put the logic after the task ends<br>
>> into the scope itself.<br>
> <br>
> Yes, extend STS and implement the policy in the subclass. The subclass<br>
> can define APIs to consume the outcome after join. Remi's example calls<br>
> for short circuiting after 3 tasks complete successfully or any task<br>
> fails with UnknownHostException, so easy to do.<br>
<br>
The problem is that unlike any other classes in java.util.concurrent, STS is not thread safe by default, it requires to carefully implement any subclasses in a thread safe way.<br>
<br>
By example, the implementation provided by Holo may not work because<br>
- it requires the implementations of FanLogic and the ShutdownStrategy to be thread safe given that they are created and used by different threads.<br>
- ConcurrentLinkedQueue.size() is O(n), not O(1) !<br>
- results() can not be protected by ensureOwnerAndJoined given it is accessed by the implementation of the ShutdownStrategy<br>
- you can have more than 3 results because a thread can be de-scheduled after the call to strategy.testResult() and before the call to results.add().<br>
<br>
Concurrency is really hard, harder than most people think. <br>
<br>
I would prefer to provide an API easier to use. I believe that having a method join() that takes a function that takes a stream is easier to use correctly.<br>
<br>
> <br>
> -Alan.<br>
<br>
Rémi<br>
</blockquote></div></div></div>