当前位置: 首页 > news >正文

宿迁网站建设兰州怎么提高网站的排名

宿迁网站建设,兰州怎么提高网站的排名,免费单页网站,新兴县做网站的作为一个才入门的菜鸟,还没写过真正的 go 项目,要理解这个 Context 还是有点难,不过还是要尝试一下。在 Go http包的Server中,每一个请求在都有一个对应的 goroutine 去处理。请求处理函数通常会启动额外的 goroutine 用来访问后端…

作为一个才入门的菜鸟,还没写过真正的 go 项目,要理解这个 Context 还是有点难,不过还是要尝试一下。在 Go http包的Server中,每一个请求在都有一个对应的 goroutine 去处理。请求处理函数通常会启动额外的 goroutine 用来访问后端服务,比如数据库服务。用来处理一个请求的 goroutine 通常需要访问一些与请求特定的数据,比如终端用户的身份认证信息、验证相关的token、请求的截止时间。 当一个请求被取消或超时时,所有用来处理该请求的 goroutine 都应该迅速退出,然后系统才能释放这些 goroutine 占用的资源。

基本示例

基本示例中,本来想使用等待组来退出 goroutine ,奈何由于无限循环的原因,导致 wg.Done 根本没办法执行,也就导致主线程没版本 over 了。

package mainimport ("fmt""sync""time"
)var wg sync.WaitGroup// 初始的例子func worker() {for {fmt.Println("worker")time.Sleep(time.Second)}// 如何接收外部命令实现退出wg.Done()
}func main() {wg.Add(1)go worker()// 如何优雅的实现结束子goroutinewg.Wait()fmt.Println("over")
}

全局变量方式

为了让 goroutine 能正常退出,可以使用全局变量,将退出信号传递到 worker 里边,这样,worker 里的 wg.Done 就可以正常执行到了。但全局变量方式控制也有其缺陷,全局变量方式存在的问题:

  • 使用全局变量在跨包调用时不容易统一。
  • 如果worker中再启动goroutine,就不太好控制了。
package mainimport ("fmt""sync""time"
)var wg sync.WaitGroup
var exit bool// 全局变量方式存在的问题:
// 1. 使用全局变量在跨包调用时不容易统一
// 2. 如果worker中再启动goroutine,就不太好控制了。func worker() {for {fmt.Println("worker")time.Sleep(time.Second)if exit {break}}wg.Done()
}func main() {wg.Add(1)go worker()time.Sleep(3 * time.Second)exit = truewg.Wait()fmt.Println("over")
}
worker
worker
worker
over

通道方式

package mainimport ("fmt""sync""time"
)var wg sync.WaitGroup// 管道方式存在的问题:
// 1. 使用全局变量在跨包调用时不容易实现规范和统一,需要维护一个共用的channelfunc worker(exitChan chan struct{}) {
LOOP:for {fmt.Println("worker")time.Sleep(time.Second)select {case <-exitChan: // 等待接收上级通知break LOOPdefault:}}wg.Done()
}func main() {var exitChan = make(chan struct{})wg.Add(1)go worker(exitChan)time.Sleep(time.Second * 3) // sleep3秒以免程序过快退出exitChan <- struct{}{}      // 给子goroutine发送退出信号close(exitChan)wg.Wait()fmt.Println("over")
}
worker
worker
worker
over

官方版本

package mainimport ("context""fmt""sync""time"
)var wg sync.WaitGroupfunc worker(ctx context.Context) {
LOOP:for {fmt.Println("worker")time.Sleep(time.Second)select {case <-ctx.Done(): // 等待上级通知break LOOPdefault:}}wg.Done()
}func main() {ctx, cancel := context.WithCancel(context.Background())wg.Add(1)go worker(ctx)time.Sleep(time.Second * 3)cancel() // 通知子goroutine结束wg.Wait()fmt.Println("over")
}
worker
worker
worker
over

当子goroutine又开启另外一个goroutine时,只需要将ctx传入即可。

package mainimport ("context""fmt""sync""time"
)var wg sync.WaitGroupfunc worker(ctx context.Context) {go worker2(ctx)
LOOP:for {fmt.Println("worker")time.Sleep(time.Second)select {case <-ctx.Done(): // 等待上级通知break LOOPdefault:}}wg.Done()
}func worker2(ctx context.Context) {
LOOP:for {fmt.Println("worker2")time.Sleep(time.Second)select {case <-ctx.Done(): // 等待上级通知break LOOPdefault:}}
}
func main() {ctx, cancel := context.WithCancel(context.Background())wg.Add(1)go worker(ctx)time.Sleep(time.Second * 3)cancel() // 通知子goroutine结束wg.Wait()fmt.Println("over")
}

With系列函数

WithCancel

func WithCancel(parent Context) (ctx Context, cancel CancelFunc)

WithCancel返回带有新Done通道的父节点的副本。当调用返回的cancel函数或当关闭父上下文的Done通道时,将关闭返回上下文的Done通道,无论先发生什么情况。取消此上下文将释放与其关联的资源,因此代码应该在此上下文中运行的操作完成后立即调用cancel。

package mainimport ("context""fmt"
)func gen(ctx context.Context) <-chan int {dst := make(chan int)n := 1go func() {for {select {case <-ctx.Done():return // return结束该goroutine,防止泄露case dst <- n:n++}}}()return dst
}func main() {ctx, cancel := context.WithCancel(context.Background())defer cancel() // 当我们取完需要的整数后调用cancelfor n := range gen(ctx) {fmt.Println(n)if n == 5 {break}}
}

gen函数在单独的goroutine中生成整数并将它们发送到返回的通道。 gen的调用者在使用生成的整数之后需要取消上下文,以免gen启动的内部goroutine发生泄漏。

WithDeadline

func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)

返回父上下文的副本,并将deadline调整为不迟于d(相当于截止时间到达时,会主动关闭 Done 通道)。如果父上下文的deadline已经早于d,则WithDeadline(parent, d)在语义上等同于父上下文。当截止日过期时,当调用返回的cancel函数时,或者当父上下文的Done通道关闭时,返回上下文的Done通道将被关闭,以最先发生的情况为准。取消此上下文将释放与其关联的资源,因此代码应该在此上下文中运行的操作完成后立即调用cancel。

package mainimport ("context""fmt""time"
)func main() {d := time.Now().Add(50 * time.Millisecond)ctx, cancel := context.WithDeadline(context.Background(), d)// 尽管ctx会过期,但在任何情况下调用它的cancel函数都是很好的实践。// 如果不这样做,可能会使上下文及其父类存活的时间超过必要的时间。defer cancel()select {case <-time.After(1 * time.Second):fmt.Println("overslept")case <-ctx.Done():fmt.Println(ctx.Err())}
}

上面的代码中,定义了一个50毫秒之后过期的deadline,然后我们调用context.WithDeadline(context.Background(), d)得到一个上下文(ctx)和一个取消函数(cancel),然后使用一个select让主程序陷入等待:等待1秒后打印overslept退出或者等待ctx过期后退出。在上面的示例代码中,因为ctx 50毫秒后就会过期,所以ctx.Done()会先接收到context到期通知,并且会打印ctx.Err()的内容。

WithTimeout

func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)

WithTimeout 返回 WithDeadline(parent, time.Now().Add(timeout))。相当于通过当前时间和超时时间来定义了 deadline 。取消此上下文将释放与其相关的资源,因此代码应该在此上下文中运行的操作完成后立即调用cancel,通常用于数据库或者网络连接的超时控制

package mainimport ("context""fmt""sync""time"
)// context.WithTimeoutvar wg sync.WaitGroupfunc worker(ctx context.Context) {
LOOP:for {fmt.Println("db connecting ...")time.Sleep(time.Millisecond * 10) // 假设正常连接数据库耗时10毫秒select {case <-ctx.Done(): // 50毫秒后自动调用break LOOPdefault:}}fmt.Println("worker done!")wg.Done()
}func main() {// 设置一个50毫秒的超时ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)wg.Add(1)go worker(ctx)time.Sleep(time.Second * 5)cancel() // 通知子goroutine结束wg.Wait()fmt.Println("over")
}
db connecting ...
db connecting ...
db connecting ...
db connecting ...
db connecting ...
worker done!
over

WithValue

WithValue返回父节点的副本,其中与key关联的值为val。仅对API和进程间传递请求域的数据使用上下文值,而不是使用它来传递可选参数给函数。所提供的键必须是可比较的,并且不应该是string类型或任何其他内置类型,以避免使用上下文在包之间发生冲突。WithValue的用户应该为键定义自己的类型。为了避免在分配给interface{}时进行分配,上下文键通常具有具体类型struct{}。或者,导出的上下文关键变量的静态类型应该是指针或接口。

package mainimport ("context""fmt""sync""time"
)// context.WithValuetype TraceCode stringvar wg sync.WaitGroupfunc worker(ctx context.Context) {key := TraceCode("TRACE_CODE")traceCode, ok := ctx.Value(key).(string) // 在子goroutine中获取trace codeif !ok {fmt.Println("invalid trace code")}
LOOP:for {fmt.Printf("worker, trace code:%s\n", traceCode)time.Sleep(time.Millisecond * 10) // 假设正常连接数据库耗时10毫秒select {case <-ctx.Done(): // 50毫秒后自动调用break LOOPdefault:}}fmt.Println("worker done!")wg.Done()
}func main() {// 设置一个50毫秒的超时ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)// 在系统的入口中设置trace code传递给后续启动的goroutine实现日志数据聚合ctx = context.WithValue(ctx, TraceCode("TRACE_CODE"), "12345")wg.Add(1)go worker(ctx)time.Sleep(time.Second * 5)cancel() // 通知子goroutine结束wg.Wait()fmt.Println("over")
}
worker, trace code:12345
worker, trace code:12345
worker, trace code:12345
worker done!
over

http://www.hkea.cn/news/849226/

相关文章:

  • 江苏网站开发外链网站大全
  • 网站代备案流程图百度关键词优化排名技巧
  • 石狮建设局网站今日头条站长平台
  • 修改公司网站网页站长素材音效
  • 网站速度测速免费访问国外网站的app
  • 常州网站搭建公司宣传推广渠道有哪些
  • 中国建设监理网站广告网络
  • 网站维护费用怎么收路由优化大师官网
  • 如何加入小说网站做打字员合肥网站优化推广方案
  • 网站建设现状关键词在线优化
  • 网站建设就业百度网址导航主页
  • 郑州公司做网站汉狮中囯联通腾迅
  • 专业网上购物平台优化网站的步骤
  • 用web开发一个网站怎么做网站推广优化平台
  • 建设企业网站进去无法显示搜索引擎seo
  • 网站 分辨率百度视频推广
  • 中国红河网seo排名工具
  • 做网站商丘3a汽车集团公司网络营销方案
  • 网络宣传推广策划范文seo如何优化排名
  • 网站 建设 原则新闻今天的最新新闻
  • 服装网站首页设计主要推广手段免费
  • 网站建设公司做销售好不好?seo搜索引擎优化实训总结
  • 江西威乐建设集团有限公司企业网站长春关键词优化公司
  • 深圳网站建设lxhd英文关键词seo
  • 在线购物商城网站百度移动端排名软件
  • 太原网站的公司友情链接的英文
  • 网站是用什么做的吗百度q3财报2022
  • 深圳福田网站建设公司如何做谷歌seo推广
  • 西安有做网站的吗北京网站设计公司
  • 哪家专门做特卖网站平台连接