golang 快速排序

1.快速排序<br/> 2.随机划分的快速排序<br/> 3.去协程快速排序<br/> 4.相同元素的快速排序<br/> 5.尾递归的快速排序

quick_sort.go
func partition(A []int, p, r int) int {
	x, i := A[r-1], p
	for j := p; j < r-1; j++ {
		if A[j] <= x {
			A[i], A[j] = A[j], A[i]
			i++
		}
	}
	A[i], A[r-1] = A[r-1], A[i]
	return i
}

// QuickSort O(nlgn)
func QuickSort(A []int, p, r int) {
	if p+1 < r {
		q := partition(A, p, r)
		QuickSort(A, p, q)
		QuickSort(A, q+1, r)
	}
}
quick_sort_rand.go

import "math/rand"

func partition(A []int, p, r int) int {
	x, i := A[r-1], p
	for j := p; j < r-1; j++ {
		if A[j] <= x {
			A[i], A[j] = A[j], A[i]
			i++
		}
	}
	A[i], A[r-1] = A[r-1], A[i]
	return i
}

func randPartition(A []int, p, r int) int {
	i := rand.Intn(r-p) + p
	A[i], A[r-1] = A[r-1], A[i]
	return partition(A, p, r)
}

// RandQuickSort O(nlgn)
func RandQuickSort(A []int, p, r int) {
	if p+1 < r {
		q := randPartition(A, p, r)
		RandQuickSort(A, p, q)
		RandQuickSort(A, q+1, r)
	}
}
quick_sort_rand_go.go
import "math/rand"

func partition(A []int, p, r int) int {
	x, i := A[r-1], p
	for j := p; j < r-1; j++ {
		if A[j] <= x {
			A[i], A[j] = A[j], A[i]
			i++
		}
	}
	A[i], A[r-1] = A[r-1], A[i]
	return i
}

func randPartition(A []int, p, r int) int {
	i := rand.Intn(r-p) + p
	A[i], A[r-1] = A[r-1], A[i]
	return partition(A, p, r)
}

// RandQuickSortGo O(nlgn)
func RandQuickSortGo(A []int, p, r int, chans chan<- int) {
	if p+1 < r {
		q := randPartition(A, p, r)
		if r-p > 1000 {
			c := make(chan int, 2)
			go RandQuickSortGo(A, p, q, c)
			go RandQuickSortGo(A, q+1, r, c)
			for i := 0; i < 2; i++ {
				<-c
			}
		} else {
			RandQuickSortGo(A, p, q, nil)
			RandQuickSortGo(A, q+1, r, nil)
		}
	}
	if chans != nil {
		chans <- 0
	}
}
same_element.go
import "math/rand"

func partitionSameElement(A []int, p, r int) (int, int) {
	x, i, j := A[r-1], p, r
	for k := p; k < j; k++ {
		if A[k] <= x {
			A[i], A[k] = A[k], A[i]
			if A[i] != x {
				i++
			}
		} else if A[k] > x {
			j--
			A[j], A[k] = A[k], A[j]
		}
	}
	return i, j
}

func randPartitionSameElement(A []int, p, r int) (int, int) {
	i := rand.Intn(r-p) + p
	A[i], A[r-1] = A[r-1], A[i]
	return partitionSameElement(A, p, r)
}

// RandQuickSortSameElement O(nlgn)
func RandQuickSortSameElement(A []int, p, r int) {
	if p+1 < r {
		q, t := randPartitionSameElement(A, p, r)
		RandQuickSortSameElement(A, p, q)
		RandQuickSortSameElement(A, t, r)
	}
}
quick_sort_tail.go
import "math/rand"

func partitionSameElement(A []int, p, r int) (int, int) {
	x, i, j := A[r-1], p, r
	for k := p; k < j; k++ {
		if A[k] <= x {
			A[i], A[k] = A[k], A[i]
			if A[i] != x {
				i++
			}
		} else if A[k] > x {
			j--
			A[j], A[k] = A[k], A[j]
		}
	}
	return i, j
}

func randPartitionSameElement(A []int, p, r int) (int, int) {
	i := rand.Intn(r-p) + p
	A[i], A[r-1] = A[r-1], A[i]
	return partitionSameElement(A, p, r)
}

// TailRescursiveQuickSort O(nlgn)
func TailRescursiveQuickSort(A []int, p, r int) {
	for p+1 < r {
		q, t := randPartitionSameElement(A, p, r)
		TailRescursiveQuickSort(A, p, q)
		p = t
	}
}

golang 寻找逆序对

查找数组中逆序对数目,利用归并排序,时间复杂度为O(nlgn)

inversion.go
func count(A []int, p, q, r int) int {
	const INTMAX = int(^uint(0) >> 1)
	A1, A2 := make([]int, q-p), make([]int, r-q)
	copy(A1, A[p:q])
	copy(A2, A[q:r])
	A1, A2 = append(A1, INTMAX), append(A2, INTMAX)
	i, j, k := 0, 0, 0
	count := 0
	n1 := len(A1) - 1
	for k = p; k < r; k++ {
		if A1[i] > A2[j] {
			A[k] = A2[j]
			j++
			count += n1 - i
		} else {
			A[k] = A1[i]
			i++
		}
	}
	return count
}

// MergeCount O(n^2)
func MergeCount(A []int, p, r int) int {
	c := 0
	if r > p+1 {
		q := (r + p) / 2
		c += MergeCount(A, p, q)
		c += MergeCount(A, q, r)
		c += count(A, p, q, r)
	}
	return c
}
inversion_go.go
func mergeCountGo(A []int, p, r int, m chan<- int) int {
	c := 0
	if r > p+1 {
		q := (r + p) / 2
		if r-p > 1000 {
			a, b := make(chan int), make(chan int)
			go mergeCountGo(A, p, q, a)
			go mergeCountGo(A, q, r, b)
			c += <-a
			c += <-b
		} else {
			c += mergeCountGo(A, p, q, nil)
			c += mergeCountGo(A, q, r, nil)
		}
		c += count(A, p, q, r)
		if m != nil {
			m <- c
		}
	}
	return c
}

// MergeCountGo O(n^2)
func MergeCountGo(A []int, p, r int) int {
	c := 0
	if r > p+1 {
		q := (r + p) / 2
		if r-p > 1000 {
			a, b := make(chan int), make(chan int)
			go mergeCountGo(A, p, q, a)
			go mergeCountGo(A, q, r, b)
			c += <-a
			c += <-b
		} else {
			c += MergeCountGo(A, p, q)
			c += MergeCountGo(A, q, r)
		}
		c += count(A, p, q, r)
	}
	return c
}

golang 归并排序

merge_sort.go
func merge(A []int, p, q, r int) {
	const INTMAX = int(^uint(0) >> 1)
	A1, A2 := make([]int, q-p), make([]int, r-q)
	copy(A1, A[p:q])
	copy(A2, A[q:r])
	A1, A2 = append(A1, INTMAX), append(A2, INTMAX)
	i, j, k := 0, 0, 0
	for k = p; k < r; k++ {
		if A1[i] >= A2[j] {
			A[k] = A2[j]
			j++
		} else {
			A[k] = A1[i]
			i++
		}
	}
}

// MergeSort O(nlgn)
func MergeSort(A []int, p, r int) {
	if r > p+1 {
		q := (r + p) / 2
		MergeSort(A, p, q)
		MergeSort(A, q, r)
		merge(A, p, q, r)
	}
}
merge_sort_go.go
func mergeSortGo(A []int, p, r int, m chan<- int) {
	if r > p+1 {
		q := (r + p) / 2
		if r-p > 1000 {
			a, b := make(chan int), make(chan int)
			go mergeSortGo(A, p, q, a)
			go mergeSortGo(A, q, r, b)
			<-a
			<-b
		} else {
			mergeSortGo(A, p, q, nil)
			mergeSortGo(A, q, r, nil)
		}
		merge(A, p, q, r)
		if m != nil {
			m <- 0
		}
	}
}

// MergeSortGo O(nlgn)
func MergeSortGo(A []int, p, r int) {
	if r > p+1 {
		q := (r + p) / 2
		if r-p > 1000 {
			a, b := make(chan int), make(chan int)
			go mergeSortGo(A, p, q, a)
			go mergeSortGo(A, q, r, b)
			<-a
			<-b
		} else {
			MergeSortGo(A, p, q)
			MergeSortGo(A, q, r)
		}
		merge(A, p, q, r)
	}
}

golang 统一

test.go
// 유니코드인지 확인
// http://pyrasis.com/book/GoForTheReallyImpatient/Unit45

package main

import (
	"fmt"
	"unicode"
)

func main() {
	var r1 rune = '한'
	fmt.Println(unicode.Is(unicode.Hangul, r1)) // true: r1은 한글이므로 true
	fmt.Println(unicode.Is(unicode.Latin, r1))  // false: r1은 라틴 문자가
	                                            // 아니므로 false

	var r2 rune = '漢'
	fmt.Println(unicode.Is(unicode.Han, r2))    // true: r2는 한자이므로 true
	fmt.Println(unicode.Is(unicode.Hangul, r2)) // false: r2는 한글이 아니므로 false

	var r3 rune = 'a'
	fmt.Println(unicode.Is(unicode.Latin, r3))  // true: r3은 라틴 문자이므로 true
	fmt.Println(unicode.Is(unicode.Hangul, r3)) // false: r3은 한글이 아니므로 false

	fmt.Println(unicode.In(r1, unicode.Latin, unicode.Han, unicode.Hangul)) // true: r1은 한글이므로 true
}
special.go
// 특성 확인
// http://pyrasis.com/book/GoForTheReallyImpatient/Unit45

package main

import (
	"fmt"
	"unicode"
)

func main() {
	fmt.Println(unicode.IsGraphic('1'))  // true: 1은 화면에 표시되는 숫자이므로 true
	fmt.Println(unicode.IsGraphic('a'))  // true: a는 화면에 표시되는 문자이므로 true
	fmt.Println(unicode.IsGraphic('한')) // true: '한'은 화면에 표시되는 문자이므로 true
	fmt.Println(unicode.IsGraphic('漢')) // true: '漢'은 화면에 표시되는 문자이므로 true
	fmt.Println(unicode.IsGraphic('\n')) // false: \n 화면에 표시되는 문자가 아니므로 false

	fmt.Println(unicode.IsLetter('a')) // true: a는 문자이므로 true
	fmt.Println(unicode.IsLetter('1')) // false: 1은 문자가 아니므로 false

	fmt.Println(unicode.IsDigit('1'))     // true: 1은 숫자이므로 true
	fmt.Println(unicode.IsControl('\n'))  // true: \n은 제어 문자이므로 true
	fmt.Println(unicode.IsMark('\u17c9')) // true: \u17c9는 마크이므로 true

	fmt.Println(unicode.IsPrint('1')) // true: 1은 Go 언어에서 표시할 수 있으므로 true
	fmt.Println(unicode.IsPunct('.')) // true: .은 문장 부호이므로 true

	fmt.Println(unicode.IsSpace(' '))   // true: ' '는 공백이므로 true
	fmt.Println(unicode.IsSymbol('♥')) // true: ♥는 심볼이므로 true

	fmt.Println(unicode.IsUpper('A')) // true: A는 대문자이므로 true
	fmt.Println(unicode.IsLower('a')) // true: a는 소문자이므로 true
}

golang 用于测试阻塞调用的有用助手

with-timeout_test.go
// WithTimeout runs a function and fails if it didn't finish within the timeout
func (s *Suite) WithTimeout(timeout time.Duration, fn func()) {
	ch := make(chan struct{})
	go func() {
		fn()
		ch <- struct{}{}
	}()

	select {
	case <-time.After(timeout):
		s.Fail("The test stuck for more than expected timeout")
	case <-ch:
		return
	}
}

golang 转换Int,String

int64_to_string.go
// To decimal string:
n := int64(32)
str := strconv.FormatInt(n, 10)
fmt.Println(str)  // Prints "32"

// To hexadecimal string:
n := int64(32)
str := strconv.FormatInt(n, 16)
fmt.Println(str)  // Prints "20"

golang 字符串构建器

builder.go
package main

import (
    "bytes"
    "fmt"
)

func main() {
    var buffer bytes.Buffer

    for i := 0; i < 1000; i++ {
        buffer.WriteString("a")
    }

    fmt.Println(buffer.String())
}

golang 生成具有零大小窗口的数据包

main.go
package main

import (
	"log"
	"math/rand"
	"net"
	"time"
)

func main() {
	rand.Seed(time.Now().UnixNano())
	packet := TCPHeader{
		// Source:      0xaa47, // Random ephemeral port
		Source:      uint16(rand.Uint32() << 2),
		Destination: 80,
		SeqNum:      rand.Uint32(),
		AckNum:      0,
		DataOffset:  5,   // 4 bits
		Reserved:    0,   // 3 bits
		ECN:         0,   // 3 bits
		Ctrl:        SYN, // 6 bits (000010, SYN bit set)
		// Window:      0xaaaa, // size of your receive window
		Window:   0,
		Checksum: 0, // Kernel will set this if it's 0
		Urgent:   0,
		Options:  []TCPOption{},
	}

	log.Printf("%d %d", packet.Source, packet.SeqNum)
	data := packet.Marshal()
	loAddr := net.IPv4(127, 0, 0, 1)
	packet.Checksum = Csum(data, netIPto4Byte(loAddr), netIPto4Byte(loAddr))
	data = packet.Marshal()

	conn, err := net.Dial("ip4:tcp", "127.0.0.1")
	if err != nil {
		log.Fatalf("Dial: %s\n", err)
	}

	conn.Write(data)

}

func netIPto4Byte(ip net.IP) [4]byte {
	b := []byte(ip[12:])
	return [4]byte{
		b[0],
		b[1],
		b[2],
		b[3],
	}
}
tcp.go
/*
Copyright 2013-2014 Graham King

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

For full license details see <http://www.gnu.org/licenses/>.
*/

package main

import (
	"bytes"
	"encoding/binary"
)

const (
	FIN = 1  // 00 0001
	SYN = 2  // 00 0010
	RST = 4  // 00 0100
	PSH = 8  // 00 1000
	ACK = 16 // 01 0000
	URG = 32 // 10 0000
)

type TCPHeader struct {
	Source      uint16
	Destination uint16
	SeqNum      uint32
	AckNum      uint32
	DataOffset  uint8 // 4 bits
	Reserved    uint8 // 3 bits
	ECN         uint8 // 3 bits
	Ctrl        uint8 // 6 bits
	Window      uint16
	Checksum    uint16 // Kernel will set this if it's 0
	Urgent      uint16
	Options     []TCPOption
}

type TCPOption struct {
	Kind   uint8
	Length uint8
	Data   []byte
}

// Parse packet into TCPHeader structure
func NewTCPHeader(data []byte) *TCPHeader {
	var tcp TCPHeader
	r := bytes.NewReader(data)
	binary.Read(r, binary.BigEndian, &tcp.Source)
	binary.Read(r, binary.BigEndian, &tcp.Destination)
	binary.Read(r, binary.BigEndian, &tcp.SeqNum)
	binary.Read(r, binary.BigEndian, &tcp.AckNum)

	var mix uint16
	binary.Read(r, binary.BigEndian, &mix)
	tcp.DataOffset = byte(mix >> 12)  // top 4 bits
	tcp.Reserved = byte(mix >> 9 & 7) // 3 bits
	tcp.ECN = byte(mix >> 6 & 7)      // 3 bits
	tcp.Ctrl = byte(mix & 0x3f)       // bottom 6 bits

	binary.Read(r, binary.BigEndian, &tcp.Window)
	binary.Read(r, binary.BigEndian, &tcp.Checksum)
	binary.Read(r, binary.BigEndian, &tcp.Urgent)

	return &tcp
}

func (tcp *TCPHeader) HasFlag(flagBit byte) bool {
	return tcp.Ctrl&flagBit != 0
}

func (tcp *TCPHeader) Marshal() []byte {

	buf := new(bytes.Buffer)
	binary.Write(buf, binary.BigEndian, tcp.Source)
	binary.Write(buf, binary.BigEndian, tcp.Destination)
	binary.Write(buf, binary.BigEndian, tcp.SeqNum)
	binary.Write(buf, binary.BigEndian, tcp.AckNum)

	var mix uint16
	mix = uint16(tcp.DataOffset)<<12 | // top 4 bits
		uint16(tcp.Reserved)<<9 | // 3 bits
		uint16(tcp.ECN)<<6 | // 3 bits
		uint16(tcp.Ctrl) // bottom 6 bits
	binary.Write(buf, binary.BigEndian, mix)

	binary.Write(buf, binary.BigEndian, tcp.Window)
	binary.Write(buf, binary.BigEndian, tcp.Checksum)
	binary.Write(buf, binary.BigEndian, tcp.Urgent)

	for _, option := range tcp.Options {
		binary.Write(buf, binary.BigEndian, option.Kind)
		if option.Length > 1 {
			binary.Write(buf, binary.BigEndian, option.Length)
			binary.Write(buf, binary.BigEndian, option.Data)
		}
	}

	out := buf.Bytes()

	// Pad to min tcp header size, which is 20 bytes (5 32-bit words)
	pad := 20 - len(out)
	for i := 0; i < pad; i++ {
		out = append(out, 0)
	}

	return out
}

// TCP Checksum
func Csum(data []byte, srcip, dstip [4]byte) uint16 {

	pseudoHeader := []byte{
		srcip[0], srcip[1], srcip[2], srcip[3],
		dstip[0], dstip[1], dstip[2], dstip[3],
		0,                  // zero
		6,                  // protocol number (6 == TCP)
		0, byte(len(data)), // TCP length (16 bits), not inc pseudo header
	}

	sumThis := make([]byte, 0, len(pseudoHeader)+len(data))
	sumThis = append(sumThis, pseudoHeader...)
	sumThis = append(sumThis, data...)
	//fmt.Printf("% x\n", sumThis)

	lenSumThis := len(sumThis)
	var nextWord uint16
	var sum uint32
	for i := 0; i+1 < lenSumThis; i += 2 {
		nextWord = uint16(sumThis[i])<<8 | uint16(sumThis[i+1])
		sum += uint32(nextWord)
	}
	if lenSumThis%2 != 0 {
		//fmt.Println("Odd byte")
		sum += uint32(sumThis[len(sumThis)-1])
	}

	// Add back any carry, and any carry from adding the carry
	sum = (sum >> 16) + (sum & 0xffff)
	sum = sum + (sum >> 16)

	// Bitwise complement
	return uint16(^sum)
}

golang 正则表达式

phone.go
// http://www.golangprograms.com/regular-expression-to-validate-phone-number.html
// Regular expression to validate phone number

package main

import (
	"fmt"
	"regexp"
)

func main() {
	str1 := "1(234)5678901x1234"
	str2 := "(+351) 282 43 50 50"
	str3 := "90191919908"
	str4 := "555-8909"
	str5 := "001 6867684"
	str6 := "001 6867684x1"
	str7 := "1 (234) 567-8901"
	str8 := "1-234-567-8901 ext1234"

	re := regexp.MustCompile(`^(?:(?:\(?(?:00|\+)([1-4]\d\d|[1-9]\d?)\)?)?[\-\.\ \\\/]?)?((?:\(?\d{1,}\)?[\-\.\ \\\/]?){0,})(?:[\-\.\ \\\/]?(?:#|ext\.?|extension|x)[\-\.\ \\\/]?(\d+))?$`)

	fmt.Printf("Pattern: %v\n", re.String()) // print pattern
	fmt.Printf("\nPhone: %v\t:%v\n", str1, re.MatchString(str1))
	fmt.Printf("Phone: %v\t:%v\n", str2, re.MatchString(str2))
	fmt.Printf("Phone: %v\t\t:%v\n", str3, re.MatchString(str3))
	fmt.Printf("Phone: %v\t\t\t:%v\n", str4, re.MatchString(str4))
	fmt.Printf("Phone: %v\t\t:%v\n", str5, re.MatchString(str5))
	fmt.Printf("Phone: %v\t\t:%v\n", str6, re.MatchString(str6))
	fmt.Printf("Phone: %v\t\t:%v\n", str7, re.MatchString(str7))
	fmt.Printf("Phone: %v\t:%v\n", str8, re.MatchString(str8))
}
email.go
// http://www.golangprograms.com/regular-expression-to-validate-email-address.html
//Regular expression to validate email address

package main

import (
	"fmt"
	"regexp"
)

func main() {
	str1 := "ç$€§/az@gmail.com"
	str2 := "abcd@gmail_yahoo.com"
	str3 := "abcd@gmail-yahoo.com"
	str4 := "abcd@gmailyahoo"
	str5 := "abcd@gmail.yahoo"

	re := regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")

	fmt.Printf("Pattern: %v\n", re.String()) // print pattern	
	fmt.Printf("\nEmail: %v :%v\n", str1, re.MatchString(str1))
	fmt.Printf("Email: %v :%v\n", str2, re.MatchString(str2))
	fmt.Printf("Email: %v :%v\n", str3, re.MatchString(str3))
	fmt.Printf("Email: %v :%v\n", str4, re.MatchString(str4))
	fmt.Printf("Email: %v :%v\n", str5, re.MatchString(str5))
}

golang golang上下文和渠道的例子

golang上下文和渠道的例子

channel_example_test.go
package channel

import (
	"fmt"
	"sync"
	"time"
)

func ExampleUnbufferedSend() {
	c1 := make(chan string)

	wg := &sync.WaitGroup{}
	wg.Add(1)
	go func() {
		defer wg.Done()
		select {
		case c1 <- "got message":
			return
		case <-time.After(20 * time.Millisecond):
			return
		}
	}()

	wg.Wait() // explicitly defer until goroutine is done
	select {
	case msg := <-c1:
		fmt.Println(msg)
	default:
		fmt.Println("no message")
	}

	// Output: no message
}

func ExampleBufferedSend() {
	c1 := make(chan string, 1)

	wg := &sync.WaitGroup{}
	wg.Add(1)
	go func() {
		defer wg.Done()
		select {
		case c1 <- "got message":
			return
		case <-time.After(20 * time.Millisecond):
			return
		}
	}()

	wg.Wait() // explicitly defer until goroutine is done
	select {
	case msg := <-c1:
		fmt.Println(msg)
	default:
		fmt.Println("no message")
	}

	// Output: got message
}

func ExampleNilChannelSend() {
	var c1 chan string

	wg := &sync.WaitGroup{}
	wg.Add(1)

	result := make(chan string, 1)
	go func() {
		defer wg.Done()
		select {
		case c1 <- "got message":
			return
		case <-time.After(20 * time.Millisecond):
			result <- "nil channel send blocks"
			return
		}
	}()

	wg.Wait()
	select {
	case msg := <-c1:
		fmt.Println(msg)
	case msg := <-result:
		fmt.Println(msg)
	}

	// Output: nil channel send blocks
}

func ExampleClosedChannelSend() {
	c1 := make(chan string, 1)
	close(c1)

	// using a channel so we know when its done
	result := make(chan string)
	go func() {
		defer func() {
			if r := recover(); r != nil { // handling the panic of the send on closed channel that will happen below
				result <- r.(error).Error()
				return
			}
			result <- "timed out"
		}()
		select {
		case c1 <- "got message": // closed channels panic when you send on them
			return
		case <-time.After(20 * time.Millisecond):
			return
		}
	}()

	fmt.Println(<-result)

	// Output: send on closed channel
}

func ExampleCloseNilChannel() {
	defer func() {
		if r := recover(); r != nil { // handling the panic of the close of nil channel
			fmt.Println(r)
			return
		}
		fmt.Println("timed out")
	}()

	var c1 chan string
	close(c1) // close of nil channel panics

	// Output: close of nil channel
}

func ExampleWaitArbitraryNumberOfChannels() {

}
context_example_test.go
package tasks

import (
	"context"
	"log"
	"sync"
	"time"
)

type ctxExamplesKey string

func ExampleSimpleContext() {
	wg := &sync.WaitGroup{}

	start := time.Now()
	estop := make(chan time.Time, 1)
	ectx := context.Background()

	ctx, cancel := context.WithCancel(ectx) // with cancel needed to be able to do
	stop1 := make(chan time.Time, 1)
	wg.Add(1)
	go func() {
		defer wg.Done()
		for {
			select {
			case <-ctx.Done():
				log.Println("done ctx")
				stop1 <- time.Now()
				return
			case <-time.After(1 * time.Second):
				log.Println("iteration for ctx")
			}
		}
	}()

	wg.Add(1)
	go func() {
		defer func() {
			estop <- time.Now()
			wg.Done()
		}()
		for {
			select {
			case <-ectx.Done():
				log.Println("done ectx, should not occur")
				return
			case <-time.After(1 * time.Second):
				log.Println("iteration for ectx because nil channel blocks forever")
				select {
				case <-ctx.Done():
					log.Println("done ectx through escaping with ctx.Done()")
					return
				default:
				}
			}
		}
	}()

	ctx2 := context.WithValue(ctx, ctxExamplesKey("ctx2val"), 0)
	stop2 := make(chan time.Time, 1)
	wg.Add(1)
	go func() {
		defer wg.Done()
		for {
			select {
			case <-ctx2.Done():
				log.Println("done ctx2")
				stop2 <- time.Now()
				return
			default:
				time.Sleep(2 * time.Second)
				log.Println("iteration for ctx2")
				ctx2 = context.WithValue(ctx2, ctxExamplesKey("ctx2val"), ctx2.Value(ctxExamplesKey("ctx2val")).(int)+1)
			}
		}
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		<-time.After(9 * time.Second)
		cancel()
		log.Println("iteration for ctx")
	}()

	wg.Wait()

	log.Printf("ctx2val (ctx): %v", ctx.Value(ctxExamplesKey("ctx2val")))
	log.Printf("ctx2val (ctx2): %d", ctx2.Value(ctxExamplesKey("ctx2val")))
	log.Println("took", time.Now().Sub(start))
	log.Printf("ectx took: %v", (<-estop).Sub(start))
	log.Printf("ctx took: %v", (<-stop1).Sub(start))
	log.Printf("ctx2 took: %v", (<-stop2).Sub(start))
}