What will happen to a golang blocking function if the invoker of this function has done?

huangapple go评论79阅读模式
英文:

What will happen to a golang blocking function if the invoker of this function has done?

问题

我想知道如果interruptable_call是不可中断的,并且在上下文完成后返回,会发生什么。调用堆栈已经被销毁了,返回操作会执行什么?当一个case返回而另一个case仍在运行时,select会如何执行?那个case函数调用会被终止吗?以什么方式?

package main

import (
	"context"
	"fmt"
	"time"
)

func interruptable_call() <-chan time.Time {
	return time.After(1 * time.Second)
}

func A(ctx context.Context) int {
	for {
		select {
		case <-ctx.Done():
			fmt.Println("func done")
			return 1
		case <-interruptable_call():
			fmt.Println("blocking")
		}
	}
	return 0
}

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	fmt.Println("go A")
	go A(ctx)
	fmt.Println("go A done")
	select {
	case <-ctx.Done():
		fmt.Println("main done")
		break
	}
}

以下是翻译好的代码部分:

package main

import (
	"context"
	"fmt"
	"time"
)

func interruptable_call() <-chan time.Time {
	return time.After(1 * time.Second)
}

func A(ctx context.Context) int {
	for {
		select {
		case <-ctx.Done():
			fmt.Println("函数完成")
			return 1
		case <-interruptable_call():
			fmt.Println("阻塞中")
		}
	}
	return 0
}

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	fmt.Println("启动 A")
	go A(ctx)
	fmt.Println("A 完成")
	select {
	case <-ctx.Done():
		fmt.Println("主函数完成")
		break
	}
}
英文:

I wonder what will happen if the interruptable_call is uninterruptable and return after the context is done. The call stack would have been already destroyed. What would the return action perform? How would select perform when one case return while another case is still running. Would that case function call be terminated? in what way?

package main

import (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;time&quot;
)

func interruptable_call() &lt;-chan time.Time {
	return time.After(1 * time.Second)
}

func A(ctx context.Context) int {
	for {
		select {
		case &lt;-ctx.Done():
			fmt.Println(&quot;func done&quot;)
			return 1
		case &lt;-interruptable_call():
			fmt.Println(&quot;blocking&quot;)
		}
	}
	return 0
}

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	fmt.Println(&quot;go A&quot;)
	go A(ctx)
	fmt.Println(&quot;go A done&quot;)
	select {
	case &lt;-ctx.Done():
		fmt.Println(&quot;main done&quot;)
		break
	}
}

答案1

得分: 1

我不确定你所说的"synchronisation problem"是什么意思,因为这里没有同步。如果你想确保你的生成的goroutine执行了任务,你需要使用通道、等待组或其他方式来同步你的goroutine。

无论goroutine中发生了什么,如果它没有与主goroutine同步,那么在主goroutine退出后它将停止存在。

异步调用的函数的返回值对你来说是不可用的。

你可以自己查看阻塞调用的工作原理:

package main

import (
	"context"
	"fmt"
	"time"
)

func interruptable_call(sleep time.Duration) <-chan time.Time {
	fmt.Println("sleeping for ", sleep*time.Second)
	time.Sleep(sleep * time.Second)
	return time.After(0 * time.Second)
}

func A(ctx context.Context) int {
	for {
		select {
		case <-ctx.Done():
			fmt.Println("func done")
			return 1
		case <-interruptable_call(2):
			fmt.Println("blocking")
		case <-interruptable_call(3):
			fmt.Println("blocking")
		case <-interruptable_call(4):
			fmt.Println("blocking")
		case <-interruptable_call(5):
			fmt.Println("blocking")
		}
	}
	return 0
}

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()
	fmt.Println("go A")
	go A(ctx)
	fmt.Println("go A done")
	select {
	case <-ctx.Done():
		fmt.Println("main done")
		break
	}
}

希望对你有帮助!

英文:

I am not sure what you mean by "synchronisation problem", since there is no synchronization here.. You need to synchronise your goroutines using channels, waitgroups or any other means if you want to be sure that your spawned goroutines performed their task.

It doesn't really matter what happens in the goroutine - if it's not synchronised with main gouroutine it will cease to exist after main exits.

Return value from function called asynchronously in goroutine won't be available to you anyway.

You can check out how blocking calls work for yourself:

package main

import (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;time&quot;
)

func interruptable_call(sleep time.Duration) &lt;-chan time.Time {
	fmt.Println(&quot;sleeping for &quot;, sleep*time.Second)
	time.Sleep(sleep * time.Second)
	return time.After(0 * time.Second)
}

func A(ctx context.Context) int {
	for {
		select {
		case &lt;-ctx.Done():
			fmt.Println(&quot;func done&quot;)
			return 1
		case &lt;-interruptable_call(2):
			fmt.Println(&quot;blocking&quot;)
		case &lt;-interruptable_call(3):
			fmt.Println(&quot;blocking&quot;)
		case &lt;-interruptable_call(4):
			fmt.Println(&quot;blocking&quot;)
		case &lt;-interruptable_call(5):
			fmt.Println(&quot;blocking&quot;)
		}
	}
	return 0
}

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()
	fmt.Println(&quot;go A&quot;)
	go A(ctx)
	fmt.Println(&quot;go A done&quot;)
	select {
	case &lt;-ctx.Done():
		fmt.Println(&quot;main done&quot;)
		break
	}
}

huangapple
  • 本文由 发表于 2017年8月1日 11:19:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/45428402.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定