> And this made me wonder: is there any reason why you can't use 
Task.async_stream?

After testing, I'm sure we can accomplish the same thing that was proposed 
with Task.async_stream. There is really no reason for an extra function.

One thing that would be nice is to have an example for this usage in the 
documentation. I honestly never thought in using Task.async_stream in this 
way. 

WDYT? PRs for adding this example to the documentation would be welcome?

Em sexta-feira, 2 de abril de 2021 às 08:39:18 UTC-3, [email protected] 
escreveu:

> Funny that exactly on this day that the proposal was opened I said in two 
> groups the lack that I was doing something similar to "Promise.any" in 
> Elixir.
>
> I needed it and found it complicated to do now, I had a job because I'm 
> starting in Elixir.
>
> I would love to have another solution for what I did, when researching 
> several APIs to return the CEP query to me and get the first valid result.
>
> I'm starting in Elixir and in love, and I made my first package with 
> exactly this need: 
> https://github.com/ciareis/cep-promise-elixir/blob/master/lib/cep_promise.ex#L52
>
> I could probably write everything in a better way, but I still get there.
>
> Please implement something to facilitate this;)
>
> Elixir S2!
> Em sexta-feira, 2 de abril de 2021 às 04:51:53 UTC-3, José Valim escreveu:
>
>> I have been thinking more about this problem and there is still one issue 
>> for us to solve: when you say you are waiting for "n" tasks, does it mean 
>> you are waiting for "n" successes or "n" results (regardless if they are 
>> success or failure)?
>>
>> So I thought perhaps a better solution is to introduce something called 
>> Task.yield_stream/2. "yield_stream" receives an enumerable of tasks and 
>> emits them as they complete. To get the first successful task you would do:
>>
>>     tasks
>>     |> Task.yield_stream(ordered: false, timeout: 5000)
>>     |> Stream.filter(&match?({:ok, _}))
>>     |> Enum.at(0)
>>
>> And this made me wonder: is there any reason why you can't use 
>> Task.async_stream?
>>
>>
>> On Thu, Apr 1, 2021 at 3:59 PM José Valim <[email protected]> wrote:
>>
>>> I don't see a reason why we wouldn't return the same order. You can 
>>> easily get the ones you want by `for {task, {:ok, value}} <- result do`. 
>>> Plus forcing people to iterate will remind them that they most likely need 
>>> to shutdown the other tasks.
>>>
>>> On Thu, Apr 1, 2021 at 3:57 PM [email protected] <
>>> [email protected]> wrote:
>>>
>>>> > In this sense, yield_many becomes a special case of yield_first where 
>>>> you want to yield on all given tasks.
>>>>
>>>> I'm not sure if we would want that, because in yield_many the returned 
>>>> list will be in the same order as the tasks supplied in the tasks 
>>>> input argument. 
>>>> However yield_first to preserve the semantics of "returning as soon it 
>>>> finishes", maybe we should return the tasks in the order of finish (the 
>>>> first to complete first in the list). 
>>>> That makes sense?
>>>>
>>>> Em quarta-feira, 31 de março de 2021 às 19:35:47 UTC-3, 
>>>> [email protected] escreveu:
>>>>
>>>>> +1 for yield_first(tasks, n, timeout)
>>>>>
>>>>> It seems to better convey the meaning "yield the first n tasks".
>>>>>
>>>>> Em qua., 31 de mar. de 2021 às 19:26, Felipe Stival <[email protected]> 
>>>>> escreveu:
>>>>>
>>>>>> +1 for yield_first(tasks, n, timeout)
>>>>>>
>>>>>>
>>>>>> On Thu, Apr 1, 2021, 01:11 José Valim <[email protected]> wrote:
>>>>>>
>>>>>>> It was not possible to implement yield_first in Elixir but now that 
>>>>>>> we have map_get in guards, we can easily do so by putting all refs in a 
>>>>>>> map 
>>>>>>> and only getting messages from the inbox where the ref is in the map. 
>>>>>>> The 
>>>>>>> number of tasks to wait and the maximum timeout should be configurable 
>>>>>>> too. 
>>>>>>> For example:
>>>>>>>
>>>>>>>     yield_first(task, 3, 1000)
>>>>>>>
>>>>>>> The above will yield the first 3 tasks within 1000ms. It should have 
>>>>>>> the same result type as yield_many. In this sense, yield_many becomes a 
>>>>>>> special case of yield_first where you want to yield on all given tasks.
>>>>>>>
>>>>>>> Another option is to not introduce a new function but instead 
>>>>>>> introduce a new argument to yield_many with the limit to yield:
>>>>>>>
>>>>>>>     yield_many(task, 1000, 3)
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On Wed, Mar 31, 2021 at 11:52 PM [email protected] <
>>>>>>> [email protected]> wrote:
>>>>>>>
>>>>>>>> I think the proposal would work differently from yield_many. 
>>>>>>>> yield_many "receives a list of tasks and waits for their replies in 
>>>>>>>> the 
>>>>>>>> given time interval". 
>>>>>>>> The proposal of the new function is to return as soon as the first 
>>>>>>>> task finishes.
>>>>>>>>
>>>>>>>> For example, if we start tasks to make call to 3 different remote 
>>>>>>>> APIs, with different response times.
>>>>>>>>
>>>>>>>> API A - 50ms
>>>>>>>> API B - 500ms
>>>>>>>> API C - 1500ms
>>>>>>>>
>>>>>>>> tasks = [
>>>>>>>>   Task.async(&api_a/0),
>>>>>>>>   Task.async(&api_b/0),
>>>>>>>>   Task.async(&api_c/0)
>>>>>>>> ]
>>>>>>>>
>>>>>>>> # returns result of API A and API B waiting for 1000ms
>>>>>>>> Task.yield_many(tasks, 1000)
>>>>>>>>
>>>>>>>> With run using `yield_many` we would wait for the 1000ms and get 
>>>>>>>> the responses of API A and API B.
>>>>>>>>
>>>>>>>> The proposal of the new function is to return as soon as we get a 
>>>>>>>> response. 
>>>>>>>> Using the same example of the 3 calls, we would wait only for 50ms 
>>>>>>>> (as soon as the first task finishes) and return the result of the 
>>>>>>>> first 
>>>>>>>> task finishing, without waiting for the other call.
>>>>>>>>
>>>>>>>> tasks = [
>>>>>>>>   Task.async(&api_a/0),
>>>>>>>>   Task.async(&api_b/0),
>>>>>>>>   Task.async(&api_c/0)
>>>>>>>> ]
>>>>>>>>
>>>>>>>> # returns only result of API A waiting for 50ms
>>>>>>>> Task.proposed_function(tasks)
>>>>>>>>
>>>>>>>> Em quarta-feira, 31 de março de 2021 às 18:06:47 UTC-3, 
>>>>>>>> [email protected] escreveu:
>>>>>>>>
>>>>>>>>> Check out Task.yield_many/2 (
>>>>>>>>> https://hexdocs.pm/elixir/Task.html#yield_many/2) :-)
>>>>>>>>>
>>>>>>>>> On 31 Mar 2021, at 22:54, [email protected] <
>>>>>>>>> [email protected]> wrote:
>>>>>>>>>
>>>>>>>>> *Proposal*
>>>>>>>>>
>>>>>>>>> Add a function to the Task module that takes a list of tasks, and 
>>>>>>>>> returns as soon as one of the tasks finishes, shuting down the other 
>>>>>>>>> tasks.
>>>>>>>>> The behaviour would pretty similar to what Javascript have with 
>>>>>>>>> Promise.any 
>>>>>>>>> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/any
>>>>>>>>>
>>>>>>>>> *Motivation*
>>>>>>>>>
>>>>>>>>> One scenario that it could be useful is when we are integrating 
>>>>>>>>> with multiple APIs (providers) of the same data, and we want only the 
>>>>>>>>> fastest result without needing to wait for the other requests to 
>>>>>>>>> complete. 
>>>>>>>>>
>>>>>>>>> Today I think this could be implemented with something similar to 
>>>>>>>>> the following code:
>>>>>>>>>
>>>>>>>>> tasks = [
>>>>>>>>>   Task.async(&heavy_fun_1/0),
>>>>>>>>>   Task.async(&heavy_fun_2/0),
>>>>>>>>>   Task.async(&heavy_fun_3/0)
>>>>>>>>> ]
>>>>>>>>>
>>>>>>>>> receive do
>>>>>>>>>   {ref, result} ->
>>>>>>>>>     tasks
>>>>>>>>>     |> Enum.reject(fn task -> task.ref == ref end)
>>>>>>>>>     |> Enum.each(&Task.shutdown/1)
>>>>>>>>>
>>>>>>>>>     result
>>>>>>>>> after
>>>>>>>>>   5000 ->
>>>>>>>>>     {:error, :timeout}
>>>>>>>>> end
>>>>>>>>>
>>>>>>>>> However that seems to be a common enough pattern to add to the 
>>>>>>>>> standard library.
>>>>>>>>>
>>>>>>>>> *Questions*
>>>>>>>>>
>>>>>>>>> - Am I missing something here and this could already be easily 
>>>>>>>>> accomplished with the existing API?
>>>>>>>>> - What should be the behaviour when the first task to complete 
>>>>>>>>> exits? 
>>>>>>>>>
>>>>>>>>> -- 
>>>>>>>>> You received this message because you are subscribed to the Google 
>>>>>>>>> Groups "elixir-lang-core" group.
>>>>>>>>> To unsubscribe from this group and stop receiving emails from it, 
>>>>>>>>> send an email to [email protected].
>>>>>>>>> To view this discussion on the web visit 
>>>>>>>>> https://groups.google.com/d/msgid/elixir-lang-core/59a5b5af-528b-4f1f-8e17-6dad9edfe9ccn%40googlegroups.com
>>>>>>>>>  
>>>>>>>>> <https://groups.google.com/d/msgid/elixir-lang-core/59a5b5af-528b-4f1f-8e17-6dad9edfe9ccn%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>>>>>>> .
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> -- 
>>>>>>>> You received this message because you are subscribed to the Google 
>>>>>>>> Groups "elixir-lang-core" group.
>>>>>>>> To unsubscribe from this group and stop receiving emails from it, 
>>>>>>>> send an email to [email protected].
>>>>>>>> To view this discussion on the web visit 
>>>>>>>> https://groups.google.com/d/msgid/elixir-lang-core/fe8d048f-605b-4b7a-ad2d-64fb11727d4dn%40googlegroups.com
>>>>>>>>  
>>>>>>>> <https://groups.google.com/d/msgid/elixir-lang-core/fe8d048f-605b-4b7a-ad2d-64fb11727d4dn%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>>>>>> .
>>>>>>>>
>>>>>>> -- 
>>>>>>> You received this message because you are subscribed to the Google 
>>>>>>> Groups "elixir-lang-core" group.
>>>>>>> To unsubscribe from this group and stop receiving emails from it, 
>>>>>>> send an email to [email protected].
>>>>>>> To view this discussion on the web visit 
>>>>>>> https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4L%2BogpwDohNaRoZHkT0%3DkOdFROdT37BQJx3k%3D%3DzZqQzAA%40mail.gmail.com
>>>>>>>  
>>>>>>> <https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4L%2BogpwDohNaRoZHkT0%3DkOdFROdT37BQJx3k%3D%3DzZqQzAA%40mail.gmail.com?utm_medium=email&utm_source=footer>
>>>>>>> .
>>>>>>>
>>>>>> -- 
>>>>>>
>>>>> You received this message because you are subscribed to a topic in the 
>>>>>> Google Groups "elixir-lang-core" group.
>>>>>> To unsubscribe from this topic, visit 
>>>>>> https://groups.google.com/d/topic/elixir-lang-core/ZIFsisK12CM/unsubscribe
>>>>>> .
>>>>>> To unsubscribe from this group and all its topics, send an email to 
>>>>>> [email protected].
>>>>>> To view this discussion on the web visit 
>>>>>> https://groups.google.com/d/msgid/elixir-lang-core/CAKC64%2BwFh20dRTVnJi5QC8Ekk5CNcSx8k8jW_xBP65rOYGukYw%40mail.gmail.com
>>>>>>  
>>>>>> <https://groups.google.com/d/msgid/elixir-lang-core/CAKC64%2BwFh20dRTVnJi5QC8Ekk5CNcSx8k8jW_xBP65rOYGukYw%40mail.gmail.com?utm_medium=email&utm_source=footer>
>>>>>> .
>>>>>>
>>>>> -- 
>>>> You received this message because you are subscribed to the Google 
>>>> Groups "elixir-lang-core" group.
>>>> To unsubscribe from this group and stop receiving emails from it, send 
>>>> an email to [email protected].
>>>> To view this discussion on the web visit 
>>>> https://groups.google.com/d/msgid/elixir-lang-core/c31c31f1-2de8-41a4-a3f3-f5b924c2ea1an%40googlegroups.com
>>>>  
>>>> <https://groups.google.com/d/msgid/elixir-lang-core/c31c31f1-2de8-41a4-a3f3-f5b924c2ea1an%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>> .
>>>>
>>>

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/8ef87d9d-32d3-4202-9f4f-d67434d207d1n%40googlegroups.com.

Reply via email to