Go Concurrency Patterns: Timing out, moving on  GO并发模式: 超时, 继续前进

23 September 2010

Concurrent programming has its own idioms. A good example is timeouts. Although Go's channels do not support them directly, they are easy to implement. Say we want to receive from the channel ch, but want to wait at most one second for the value to arrive. We would start by creating a signalling channel and launching a goroutine that sleeps before sending on the channel:

timeout := make(chan bool, 1)
go func() {
time.Sleep(1 * time.Second)
timeout <- true
}()

We can then use a select statement to receive from either ch or timeout. If nothing arrives on ch after one second, the timeout case is selected and the attempt to read from ch is abandoned.

select {
case <-ch:
// a read from ch has occurred
case <-timeout:
// the read from ch has timed out
}

The timeout channel is buffered with space for 1 value, allowing the timeout goroutine to send to the channel and then exit. The goroutine doesn't know (or care) whether the value is received. This means the goroutine won't hang around forever if the ch receive happens before the timeout is reached. The timeout channel will eventually be deallocated by the garbage collector.

(In this example we used time.Sleep to demonstrate the mechanics of goroutines and channels. In real programs you should use ` time.After`, a function that returns a channel and sends on that channel after the specified duration.)

Let's look at another variation of this pattern. In this example we have a program that reads from multiple replicated databases simultaneously. The program needs only one of the answers, and it should accept the answer that arrives first.

The function Query takes a slice of database connections and a query string. It queries each of the databases in parallel and returns the first response it receives:

func Query(conns []Conn, query string) Result {
ch := make(chan Result)
for _, conn := range conns {
go func(c Conn) {
select {
case ch <- c.DoQuery(query):
default:
}
}(conn)
}
return <-ch
}

In this example, the closure does a non-blocking send, which it achieves by using the send operation in selectstatement with a default case. If the send cannot go through immediately the default case will be selected. Making the send non-blocking guarantees that none of the goroutines launched in the loop will hang around. However, if the result arrives before the main function has made it to the receive, the send could fail since no one is ready.

This problem is a textbook example of what is known as a race condition, but the fix is trivial. We just make sure to buffer the channel ch (by adding the buffer length as the second argument to make), guaranteeing that the first send has a place to put the value. This ensures the send will always succeed, and the first value to arrive will be retrieved regardless of the order of execution.

These two examples demonstrate the simplicity with which Go can express complex interactions between goroutines.

By Andrew Gerrand

Related articles

16 Go Concurrency Patterns: Timing out, moving on GO并发模式: 超时, 继续前进的更多相关文章

  1. Go Concurrency Patterns: Timing out, moving on

    https://blog.golang.org/go-concurrency-patterns-timing-out-and

  2. Go Concurrency Patterns: Pipelines and cancellation

    https://blog.golang.org/pipelines Go Concurrency Patterns: Pipelines and cancellation Sameer Ajmani1 ...

  3. Go Concurrency Patterns: Context At Google, we require that Go programmers pass a Context parameter as the first argument to every function on the call path between incoming and outgoing requests.

    小结: 1. Background is the root of any Context tree; it is never canceled: 2.     https://blog.golang. ...

  4. golang语言中的context详解,Go Concurrency Patterns: Context

    https://blog.golang.org/context Introduction In Go servers, each incoming request is handled in its ...

  5. Advanced Go Concurrency Patterns

    https://talks.golang.org/2013/advconc.slide#5 It's easy to go, but how to stop? Long-lived programs ...

  6. 设计模式教程(Design Patterns Tutorial)笔记之三 行为型模式(Behavioral Patterns)

    目录 · Strategy · When to use the Strategy Design Pattern? · Sample Code · Observer · When to use the  ...

  7. [Python设计模式] 第16章 上班,干活,下班,加班——状态模式

    github地址:https://github.com/cheesezh/python_design_patterns 题目 用代码模拟一天的工作状态,上午状态好,中午想睡觉,下午渐恢复,加班苦煎熬. ...

  8. 设计模式教程(Design Patterns Tutorial)笔记之一 创建型模式(Creational Patterns)

    目录 · 概述 · Factory · What is the Factory Design Pattern? · Sample Code · Abstract Factory · What is t ...

  9. Ubuntu 16.04/CentOS 6.9安装Apache压力(并发)测试工具ab

    说明: ab工具已经在Apache中包含,如果不想安装Apache,那么可以使用下面方法单独安装. 安装: Ubuntu: sudo apt-get install apache2-utils Cen ...

随机推荐

  1. 胡小兔的NOIP2017游记【出成绩后更新版】

    胡小兔的NOIP2017游记[出成绩后更新版] 2017.11.22 Update 前几天成绩出来啦,看这篇博客访问量还挺多的,下面就分享一下结果吧: 我的Day1T2和Day2T1两道最水的题都跪了 ...

  2. 51nod 1421 最大MOD值 | 暴力

    题面 有一个a数组,里面有n个整数.现在要从中找到两个数字(可以是同一个) ai,aj ,使得 ai mod aj 最大并且 ai ≥ aj. Input 单组测试数据. 第一行包含一个整数n,表示数 ...

  3. Ubuntu中Android SDK Manager无法更新解决办法

    Ubuntu中Android SDK Manager无法更新解决办法http://hi.baidu.com/petercao2008/item/d7a64441f04668e81e19bc1a

  4. python之旅:并发编程之多进程

    一 multiprocessing模块介绍 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大部分情况需要使用多进程.P ...

  5. Linux上给php配置redis扩展

    说明,在项目开发中难免会遇到redis中,那我应该如何配置redis这样的一个扩展呢,看下面流程: 一.安装Redis PHP在安装redis扩展时,难免要看一下官网下载安装流程,链接如下: http ...

  6. servlet的application对象的使用

    application对象 1 什么是application对象 ? (1) 当Web服务器启动时,Web服务器会自动创建一个application对象.application对象一旦创建,它将一直存 ...

  7. Java 守护线程概述

    原文出处: 朱小厮 Java的线程分为两种:User Thread(用户线程).DaemonThread(守护线程). 只要当前JVM实例中尚存任何一个非守护线程没有结束,守护线程就全部工作:只有当最 ...

  8. Java6的新特性

    原文出处:xixicat 序 本文梳理了下java6的新特性,相对于java5而言,java6的特性显得少些,分量也不那么重,相当于java5是windows xp,java6有点像vista. 特性 ...

  9. Hadoop基础-SequenceFile的压缩编解码器

    Hadoop基础-SequenceFile的压缩编解码器 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Hadoop压缩简介 1>.文件压缩的好处 第一:较少存储文件占用 ...

  10. Java基础-包(package)的声明与访问

    Java基础-包(package)的声明与访问 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.包的概念 Java中的包,其实就是我们电脑系统中的文件夹,包里存放的是程序员生成的 ...