Just a related observation. I don't think you need to have a select 
statement to check if a context is cancelled. I think it is sufficient to 
just check if ctx.Err() gives a result different from nil.

>From the API documentation for Context (https://pkg.go.dev/context#Context):
// If Done is not yet closed, Err returns nil. 
// If Done is closed, Err returns a non-nil error explaining why: 
// Canceled if the context was canceled 
// or DeadlineExceeded if the context's deadline passed. 
// After Err returns a non-nil error, successive calls to Err return the 
same error.
Err() error <https://pkg.go.dev/builtin#error>

//Jan

onsdag 12 januari 2022 kl. 09:41:23 UTC+1 skrev lege...@gmail.com:

> Hi Axel, thank you very much, your explanation of this problem is very 
> detailed and solves my question.
>
> What I think it's not so good is that I must add the select at all the 
> places the goroutine is waiting or looping, it makes the execution and 
> scheduling part of the task scheduling system coupling a bit tightly, 
> because I need to implement many different types of tasks, and I have to 
> consider the cancel logic (which I think belongs to scheduling part) 
> explicitly in each type of task executor, instead of leaving it all to the 
> scheduling part. I think it will be better if the task executor can only 
> consider the business logic.
>
> I also tried to abstract this cancel logic into generic processing so that 
> it could be easily applied to different types of tasks, but I didn't find a 
> good way to do this, I had to manually add the code wherever it was needed
>
> On Tue, Jan 11, 2022 at 10:31 PM Axel Wagner <axel.wa...@googlemail.com> 
> wrote:
>
>>
>>
>> On Wed, Jan 12, 2022 at 3:01 AM E Z <lege...@gmail.com> wrote:
>>
>>> Thank you very much.
>>>
>>> I understand that we can use context.Context to resolve the network 
>>> blocking problem in long-running function if the network library support 
>>> passing a context parameter. 
>>>
>>> But for the CPU-bound code,  Is the following implementation mentioned 
>>> by axel the only way to make a function exit earlier?
>>>
>>
>> It's not the only way, but it's the way I'd generally recommend. 
>> Universally using `context.Context` to signal cancellation solves exactly 
>> the problem you where having. Specifically,
>>
>> > The above code is executing in a goroutine, if I want to cancel this 
>> goroutine, I can send a signal to task.channel, but the signal only can be 
>> retrieved after the task.task.Run is finished, it may be a long time, such 
>> as 5 mins. 
>>
>> If `task.task.Run` takes a `context.Context`, it can exit sooner than 
>> after 5 minutes. If it takes that long because it does remote requests, it 
>> can propagate the Context itself. If it is CPU-bound, it can check if the 
>> Context was cancelled, say, every 1000 iterations (or whatever. What's a 
>> reasonable number depends heavily on what it's doing).
>>
>> But, yes, for such a CPU-bound task, actively checking if it was 
>> cancelled via a mechanism like a Context is the only way to be aborted.
>>
>> For example, goroutine is executing a task to update a DNS record and 
>>> then wait some time until the DNS record takes effect in some name 
>>> servers.  It may take some seconds even minutes to make the DNS record take 
>>> effect in the name server.
>>>
>>
>> To be clear, this is not a CPU-bound process. Updating the DNS record is 
>> either a network request/IPC. The waiting is then a loop like
>>
>> for {
>>     select {
>>     case <-ctx.Done():
>>         return ctx.Err()
>>     case <-time.After(time.Second()): // simplistic, you'd likely want 
>> some jitter and/or exponential backoff here
>>         if recordHasChanged(ctx) { // network request to check if the DNS 
>> record has changed - takes a Context, as it's a network request
>>             return nil
>>         }
>>     }
>> }
>>
>> This will spend most of its time sleeping.
>>
>> A CPU-bound task is something like a diff-operation, which is just an 
>> algorithm that can be very slow for large inputs, just because it has a lot 
>> of work to churn through.
>>
>> In this case, seems I can't cancel the running goroutine except that we 
>>> add the above select at every for loop or wait timer, or  I change the 
>>> design to split these time-consuming operations into different goroutine. 
>>> Both seem not so good.
>>>
>>
>> I don't understand why you think this is not good. It seems perfectly 
>> reasonable code. But yes, it's what you have to do. Go has no way to 
>> asynchronously stop code, you need to manually cancel. And context.Context 
>> gives a universal mechanism to do that, which I would recommend using for 
>> that.
>>  
>>
>>>
>>> On Tuesday, January 11, 2022 at 1:04:15 PM UTC-8 Ian Lance Taylor wrote:
>>>
>>>> On Tue, Jan 11, 2022 at 12:15 PM 'Axel Wagner' via golang-nuts 
>>>> <golan...@googlegroups.com> wrote: 
>>>> > 
>>>> > The best way to do this is to plumb a context.Context through all 
>>>> long-running functions - in particular, anything talking to the network. 
>>>> > Most RPC and network frameworks provide a way to pass a Context, so 
>>>> consistently doing this will more or less transparently cancel your 
>>>> business logic ASAP. 
>>>> > For purely CPU bound code, this is a bit more awkward, because you 
>>>> indeed have to intersperse code like 
>>>> > select { 
>>>> > case <-ctx.Done(): 
>>>> > return ctx.Err() 
>>>> > default: 
>>>> > } 
>>>> > to make the code return early. But that should be relatively rare. 
>>>>
>>>> Yes. See also https://go.dev/blog/context . 
>>>>
>>>> Ian 
>>>>
>>> -- 
>>> You received this message because you are subscribed to the Google 
>>> Groups "golang-nuts" group.
>>> To unsubscribe from this group and stop receiving emails from it, send 
>>> an email to golang-nuts...@googlegroups.com.
>>> To view this discussion on the web visit 
>>> https://groups.google.com/d/msgid/golang-nuts/d1898f67-d1e0-4276-af92-016b82866de4n%40googlegroups.com
>>>  
>>> <https://groups.google.com/d/msgid/golang-nuts/d1898f67-d1e0-4276-af92-016b82866de4n%40googlegroups.com?utm_medium=email&utm_source=footer>
>>> .
>>>
>>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/5ce0f16b-1e8b-4582-8307-55fd8e60df15n%40googlegroups.com.

Reply via email to