go 如何优雅的实现这个面试题

有四个线程1、2、3、4。线程1的功能就是输出1,线程2的功能就是输出2,以此类推.........现在有四个文件ABCD。初始都为空。现要让四个文件呈如下格式:


A:1 2 3 4 1 2....


B:2 3 4 1 2 3....


C:3 4 1 2 3 4....


D:4 1 2 3 4 1....


go 如何实现?大牛们请上代码

已邀请:

skylzyd - 程序员

赞同来自: thinkgo cholerae silenceshell

修改后的问题:


func main() {
cha := make(chan struct{})
chb := make(chan struct{})
chc := make(chan struct{})
chd := make(chan struct{})
go test(1, cha, chb)
go test(2, chb, chc)
go test(3, chc, chd)
go test(4, chd, cha)
cha <- struct{}{}
time.Sleep(time.Second * 2)//阻塞
}

func test(i int, ch1, ch2 chan struct{}) {
for range ch1 {
println(i)
ch2 <- struct{}{}
}
}

fabsnail

赞同来自: thinkgo jasonleeoffice

package main

import (
"bytes"
"log"
"time"
)

func main() {
ch1ss := makeChs(4)
ch2ss := makeChs(4)
ch3ss := makeChs(4)
ch4ss := makeChs(4)

go gen(1, ch1ss)
go gen(2, ch2ss)
go gen(3, ch3ss)
go gen(4, ch4ss)

chs1 := []chan int{ch1ss[0], ch2ss[0], ch3ss[0], ch4ss[0]}
buf1 := new(bytes.Buffer)
go writeFile(chs1, buf1)

chs2 := []chan int{ch2ss[1], ch3ss[1], ch4ss[1], ch1ss[1]}
buf2 := new(bytes.Buffer)
go writeFile(chs2, buf2)

chs3 := []chan int{ch3ss[2], ch4ss[2], ch1ss[2], ch2ss[2]}
buf3 := new(bytes.Buffer)
go writeFile(chs3, buf3)

chs4 := []chan int{ch4ss[3], ch1ss[3], ch2ss[3], ch3ss[3]}
buf4 := new(bytes.Buffer)
go writeFile(chs4, buf4)

time.Sleep(3 * time.Second)
printData("file1: ", buf1)
printData("file2: ", buf2)
printData("file3: ", buf3)
printData("file4: ", buf4)
}

func makeChs(len int) (rets []chan int) {
rets = make([]chan int, len)
for i := 0; i < len; i++ {
rets[i] = make(chan int)
}
return
}

func gen(seed int, rets []chan int) {
for {
for _, ch := range rets {
ch <- seed
time.Sleep(50 * time.Millisecond)
}
}
}

func writeFile(chs []chan int, buf *bytes.Buffer) {
for {
for _, ch := range chs {
data := <-ch
buf.WriteRune(rune(data))
}
}
}

func printData(prefix string, buf *bytes.Buffer) {
log.Println(prefix, buf.Bytes())
}

// 附运行输出
file1: [1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4]
file2: [2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1]
file3: [3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2]
file4: [4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3]

mygogo - http://www.sunaloe.cn

赞同来自: lifei6671

http://www.sunaloe.cn/d/19
简单写了下

loplop

赞同来自: jinheking

声明那么多chan?就不能用个make([]chan int, 3)吗?


不够优雅

tom0001

赞同来自: johney

package main

import (
"bytes"
"fmt"
)

func main() {
chs := make([]chan int, 4)
for i := 0; i < len(chs); i++ {
chs[i] = make(chan int)
go func(i int) {
for {
chs[i] <- i + 1
}
}(i)
}
f := make([]bytes.Buffer, len(chs))

for i := 0; i < 10; i++ {
for j := 0; j < len(f); j++ {
fmt.Fprintf(&f[j], "%d ", <-chs[(i+j)%len(chs)])
}
}
for i := 0; i < len(f); i++ {
fmt.Printf("%d: %s\n", i, f[i].String())
}
}

skylzyd - 程序员

赞同来自:

    a:=func(i int){
println(i)
}
go a(1)
go a(2)
go a(3)
go a(4)

toukii

赞同来自:

package main

import (
"time"
"fmt"
)

func main() {
file:= File{
locs : []string{"A","B","C","D"},
files:make(map[string][]int),
buf: make(chan int,10),
}
for _,it := range file.locs{
file.files[it]=make([]int,0,10)
}
go func() {
for i := 0; i < 200; i++ {
file.buf<-i%4+1;
time.Sleep(1e9)
}
}()
var v int
cur:=0
l:=len(file.locs)
for{
v=<-file.buf
file.files[file.locs[cur]]=append(file.files[file.locs[cur]],v)
if v==l{
file.files[file.locs[cur]]=append(file.files[file.locs[cur]],<-file.buf)
}
cur++
if cur>=4 {
cur = 0
}
time.Sleep(5e8)
file.Log()
}

}

type File struct {
locs []string
files map[string][]int
buf chan int
}

func (f File) Log() {
fmt.Println("======================")
for _,it:=range f.locs{
fmt.Println(it,":",f.files[it])
}
}

xnotepad - 80 后 IT 男

赞同来自:

好好审题:



  1. 线程;

  2. 文件内容与线程之间没关联。

yubc2006

赞同来自:

c := make(chan []int)
m := []int{1, 2, 3, 4}
go func() {
var i int
for tt := range c {
fmt.Println(i, ":", tt)
i++
if i == 4 {
i = 0
}
}
}()
go func() {
for i := 0; i < 200; i++ {
n := i % 4
mm := []int{}
mm = append(mm, m[n:]...)
mm = append(mm, m[:n]...)
c <- mm
}
}()

npchp110

赞同来自:

package main

import (
"bytes"
"fmt"
"io"
"time"
)

var (
c1, c2, c3, c4 chan int
c chan int
cA, cB, cC, cD chan int
fA, fB, fC, fD io.Writer
l []chan int
)

func merge() {
for {
c <- <-c1
c <- <-c2
c <- <-c3
c <- <-c4
}
}

func writeFile() {
for {
select {
case x := <-cA:
fmt.Fprint(fA, x)
case x := <-cB:
fmt.Fprint(fB, x)
case x := <-cC:
fmt.Fprint(fC, x)
case x := <-cD:
fmt.Fprint(fD, x)
}
}
}

func broadcast() {
x := <-c
for i := range l {
l[i] <- x
}
}

func combine() {
for _, ci := range []chan int{cA, cB, cC, cD} {
l = append(l, ci)
broadcast()
}

for {
broadcast()
}
}

func producer() {
for {
select {
case c1 <- 1:
case c2 <- 2:
case c3 <- 3:
case c4 <- 4:
}
}
}

func init() {
c1 = make(chan int, 10)
c2 = make(chan int, 10)
c3 = make(chan int, 10)
c4 = make(chan int, 10)

c = make(chan int, 10)

cA = make(chan int, 10)
cB = make(chan int, 10)
cC = make(chan int, 10)
cD = make(chan int, 10)

fA = &bytes.Buffer{}
fB = &bytes.Buffer{}
fC = &bytes.Buffer{}
fD = &bytes.Buffer{}

go producer()
}

func main() {
go merge()
go writeFile()

go combine()

select {
case <-time.After(time.Second):
}
fmt.Println(fA.(*bytes.Buffer).String()[:10])
fmt.Println(fB.(*bytes.Buffer).String()[:10])
fmt.Println(fC.(*bytes.Buffer).String()[:10])
fmt.Println(fD.(*bytes.Buffer).String()[:10])
}

tomahawk

赞同来自:

package main


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


var num int
type Printnum struct{
lock *sync.Mutex
sum int
}


func (p *Printnum) Incr() int{
p.lock.Lock()
defer p.lock.Unlock()
p.sum++
return p.sum
}


var printnum = Printnum{
lock: new(sync.Mutex),
sum:0,
}


func PrintN(i int){
for {
go func(i int){
for {
if printnum.Incr() == 100{
return
}
<- chlista[i-1]
fmt.Print("a",i)
cha <- i%4+1
}
}(i)
go func(i int){
for {
if printnum.Incr() == 100{
return
}
<- chlistb[i-1]
fmt.Print("b",i)
chb <- i%4+1
}
}(i)
go func(i int){
for {
if printnum.Incr() == 100{
return
}
<- chlistc[i-1]
fmt.Print("c",i)
chc <- i%4+1
}
}(i)
go func(i int){
for {
if printnum.Incr() == 100{
return
}
<- chlistd[i-1]
fmt.Print("d",i)
chd <- i%4+1
}
}(i)
}
}


var ch1a = make(chan int)
var ch2a = make(chan int)
var ch3a = make(chan int)
var ch4a = make(chan int)
var chlista = []chan int{ch1a,ch2a,ch3a,ch4a}


var ch1b = make(chan int)
var ch2b = make(chan int)
var ch3b = make(chan int)
var ch4b = make(chan int)
var chlistb = []chan int{ch1b,ch2b,ch3b,ch4b}


var ch1c = make(chan int)
var ch2c = make(chan int)
var ch3c = make(chan int)
var ch4c = make(chan int)
var chlistc = []chan int{ch1c,ch2c,ch3c,ch4c}


var ch1d = make(chan int)
var ch2d = make(chan int)
var ch3d = make(chan int)
var ch4d = make(chan int)
var chlistd = []chan int{ch1d,ch2d,ch3d,ch4d}


var cha = make(chan int) // 1,2,3,4
var chb = make(chan int) // 1,2,3,4
var chc = make(chan int) // 1,2,3,4
var chd = make(chan int) // 1,2,3,4


func filea(){
for{
num := <- cha
chlista[num-1] <- num
}
}


func fileb(){
for{
num := <- chb
chlistb[num-1] <- num
}
}


func filec(){
for{
num := <- chc
chlistc[num-1] <- num
}
}


func filed(){
for{
num := <- chd
chlistd[num-1] <- num
}
}


func main() {
go PrintN(1)
go PrintN(2)
go PrintN(3)
go PrintN(4)


go filea()
go fileb()
go filec()
go filed()

chd <- 1
cha <- 4
chb <- 3
chc <- 2

time.Sleep(time.Second*10)

}

simple - 分布式 & Java & Go

赞同来自:

问题的解法可以这样想:
由A,B,C,D四个点组成一个正方形,每个点都是一个goroutine,每个边都是一个channel,然后从A开始将0加1,写入文件A,然后将1写入channel传给B,B也将得到的结果+1并写入文件B,然后写入channel传给C,就这样A->B->C->D->A,这个传递下去就可以了。代码自己试着写下,正好可以锻炼一下自己嘛。

hmly

赞同来自:

是我题意理解不对么?我咋感觉很少代码就能解决啊,为什么上面的同学都写那么长?


type printChan chan func()

func printOut(num int) func() {
return func() {
println(num) //这里去做文件写入便可
}
}

func printClass(arr [4]int) {
test := make(printChan, len(arr))
for _, i := range arr {
test <- printOut(i)
}
for i := 0; i < 20; i++ {
ret := <-test
ret()
test <- ret
}
}

func TestPrint(t *testing.T) {
A := [4]int{1, 2, 3, 4}
B := [4]int{2, 3, 4, 1}
C := [4]int{3, 4, 1, 2}
D := [4]int{4, 1, 2, 3}
//A
println("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
printClass(A)
//B
println("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB")
printClass(B)
//C
println("CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC")
printClass(C)
//D
println("DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD")
printClass(D)
}

jdlau

赞同来自:

我的版本:


package main

import (
"fmt"
"os"
"time"
)

var (
count int
ch chan Model
)

// 将要写入文件的数字
type Model struct {
File *os.File
Num int
}

func init() {
count = 4
ch = make(chan Model)
}

func main() {
ch1 := gen(1)
ch2 := gen(3)
ch3 := gen(5)
ch4 := gen(7)

var fs []*os.File
for _, fileName := range []string{"A", "D", "C", "B"} {
f, err := os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
if err != nil {
panic(err)
}
fs = append(fs, f)
}

go write()

timeCh := time.After(time.Millisecond * 10)
times := 0
for {
select {
case <-timeCh:
return
default:
n := <-ch1
index := times % count
ch <- Model{fs[index], n}

n = <-ch2
index = times%count - 1
if index < 0 {
index += count
}
if index > count - 1 {
index -= count
}
ch <- Model{fs[index], n}

n = <-ch3
index = times%count - 2
if index < 0 {
index += count
}
if index > count - 1 {
index -= count
}
ch <- Model{fs[index], n}

n = <-ch4
index = times%count - 3
if index < 0 {
index += count
}
if index > count - 1 {
index -= count
}
ch <- Model{fs[index], n}
times++
}
}
}

func write() {
for m := range ch {
_, err := fmt.Fprintf(m.File, "%d", m.Num)
if err != nil {
panic(err)
}
}
}

func gen(num int) chan int {
ch := make(chan int)
go func() {
for {
ch <- num
}
}()
return ch
}

senlixiushu

赞同来自:

package main

import (
"fmt"
"sync"
)

var wait sync.WaitGroup

func DoMath(Max, Num int) {

filesMap := make([][]int, Num)
chanList := []<-chan int{}

for i := 0; i < Num; i++ {
chanList = append(chanList, ChanInt(i+1))
filesMap[i] = []int{}
}

wait.Add(Num)

for j := 0; j < Num; j++ {

go func(j int) {
for i := 0; i < Max; i++ {
filesMap[j] = append(filesMap[j], <-chanList[(j+i)%Num])
}
wait.Done()
}(j)

}

wait.Wait()

for k, v := range filesMap {
fmt.Printf("%s : %v\n", string(rune(65+k)), v)
}

}

func ChanInt(i int) <-chan int {

ch := make(chan int, 0)

go func() {
for {
ch <- i
}
}()

return ch
}

sax1412

赞同来自:

package main

import (
"strconv"
"fmt"
)

var a, b, c, d string
var num = [4]int{1, 2, 3, 4}
var strings = [4]string{a, b, c, d}

func main() {
range_num(num)
for i:=0;i<10;i++ {
num[0],num[1],num[2],num[3]=num[1],num[2],num[3],num[0]
range_num(num)
}
fmt.Println(strings)
}

func write(i int, s *string){
*s += strconv.Itoa(i)
}

func range_num(num [4]int){
for i:=0;i<4 ;i++ {
write(num[i], &strings[i])
}
}

luw2007

赞同来自:

看图,可以发现遇到4则暂停一次,然后顺序输出。
流程图


package main

import (
"bytes"
"fmt"
"strconv"
)

const STEP, NUM = 4, 40

var (
chans [STEP]chan int // 创建生产者
files [STEP]*bytes.Buffer // 创建接受者
last, cur = 0, 0
)

func main() {
for i := range chans {
chans[i] = make(chan int)
files[i] = new(bytes.Buffer)
go func(out chan<- int, prime int) {
for {
out <- prime
}
}(chans[i], i)
}
for j := 0; j < NUM; j++ {
k := <-chans[j%STEP] + 1
files[cur].WriteString(strconv.Itoa(k))
// 当前游标如果到达最大值 则停留一次,然后继续前进
if k != STEP || cur == last {
last, cur = cur, (cur+1)%4
}
}
fmt.Print(files)
}

nemowen

赞同来自:

package main

import (
"fmt"
"sync"
)

var (
ch1, ch2, ch3, ch4 chan *File = make(chan *File, 1), make(chan *File, 1), make(chan *File, 1), make(chan *File, 1)
arr []*File = []*File{&File{name: "A"}, &File{name: "B"}, &File{name: "C"}, &File{name: "D"}}
wg sync.WaitGroup
)

type File struct {
name string
contents []int
}

func (f *File) append(num int) {
f.contents = append(f.contents, num)
}

func (f *File) String() string {
return fmt.Sprintf("%s:%v", f.name, f.contents)
}

func main() {
wg.Add(4)

ch1 <- arr[0]
ch2 <- arr[1]
ch3 <- arr[2]
ch4 <- arr[3]

go work(1, ch1, ch2)
go work(2, ch2, ch3)
go work(3, ch3, ch4)
go work(4, ch4, ch1)

wg.Wait()

print()

}

func print() {
for _, f := range arr {
fmt.Println(f)
}
}

func work(num int, ch chan *File, next chan *File) {
for i := 0; i < 6; i++ {
f := <-ch
f.append(num)
next <- f
}
wg.Done()
}

llliiinnn - 死肥宅

赞同来自:

逼乎害人不浅

johney

赞同来自:

丑陋的实现。。。。


func main() {
a := make(chan int, 1)
b := make(chan int, 1)
c := make(chan int, 1)
d := make(chan int, 1)

fa, _ := os.OpenFile("a.txt", os.O_WRONLY|os.O_CREATE, 0666)
defer fa.Close()
fb, _ := os.OpenFile("b.txt", os.O_WRONLY|os.O_CREATE, 0666)
defer fb.Close()
fc, _ := os.OpenFile("c.txt", os.O_WRONLY|os.O_CREATE, 0666)
defer fc.Close()
fd, _ := os.OpenFile("d.txt", os.O_WRONLY|os.O_CREATE, 0666)
defer fd.Close()

timer := time.NewTimer(time.Millisecond * 2)
a <- 0
for {
select {
case num := <- a:
fa.WriteString(strconv.Itoa(num % 4 + 1) + " ")
num++
b <- num
case num := <- b:
fb.WriteString(strconv.Itoa(num % 4 + 1) + " ")
num++
c <- num
case num := <- c:
fc.WriteString(strconv.Itoa(num % 4 + 1) + " ")
num++
d <- num
case num := <- d:
fd.WriteString(strconv.Itoa(num % 4 + 1) + " ")
num += 2
a <- num
case <- timer.C:
fmt.Println("timeout")
os.Exit(1)
}

}
}

doit

赞同来自:

func t1() {                                 
a := []chan []int{
make(chan []int),
make(chan []int),
make(chan []int),
make(chan []int),
}

for i := 0; i < 4; i++ {
go func(n int) {
for f := range a[n] {
a[(n+1)%4] <- append(f, n+1)
}
}(i)
}
for i := 0; i < 4; i++ {
a[i] <- make([]int, 0)
}

time.Sleep(time.Second)
for _, a := range a {
c := <-a
fmt.Println(c)
}
}

YingQm - 80后程序媛

赞同来自:

package main

import "os"
import "fmt"
import "sync"

const num = 4
const size = 10

var ch [num]chan int
var outfile []*os.File
var waitgroup sync.WaitGroup

func MyPrint(v int) {
waitgroup.Add(1)
for i := 0; i < size; i++ {
outfileNo := <-ch[v]
outfile[outfileNo].WriteString(fmt.Sprintf("%d ", v+1))
ch[(v+1)%num] <- outfileNo
}
waitgroup.Done()
}

func main() {
outfile = make([]*os.File, num)
for i := 0; i < num; i++ {
ch[i] = make(chan int, 1)
ch[i] <- i
outfile[i], _ = os.Create(fmt.Sprintf("outfile_%c", 'A'+i))
go MyPrint(i)
}
waitgroup.Wait()
}

YingQm - 80后程序媛

赞同来自:

还有一种方法:


package main

import (
    "fmt"
    "os"
    "sync"
)

type chanContent struct {
    fileNo, no int
}

const num = 4
const size = 10

var waitgroup sync.WaitGroup
var outfile []*os.File
var ch [num]<-chan chanContent

func main() {
    outfile = make([]*os.File, num)
    for i := 0; i < num; i++ {
        outfile[i], _ = os.Create(fmt.Sprintf("file_%c", 'A'+i))
        ch[i] = MyPrintf(i, i)

        go func(c <-chan chanContent) {
            waitgroup.Add(1)
            count := 0
            for buf := range c {
                outfile[buf.fileNo].WriteString(fmt.Sprintf("%d ", buf.no))
                count++
                if count > size {
                    break
                }
            }
            waitgroup.Done()
        }(ch[i])
    }

    waitgroup.Wait()
}

func MyPrintf(fileNo int, no int) <-chan chanContent {
    c := make(chan chanContent)
    go func() {
        for i := 0; ; i++ {
            var buf chanContent
            buf.fileNo = fileNo
            buf.no = (i+no)%num + 1
            c <- buf
        }
    }()

    return c
}

mofiu

赞同来自:

package main

import (
"fmt"
"time"
)
func main() {
numch :=make(chan int,1)

file := []string{"A","B","C","D"}
num := []int{1,2,3,4}
go getNum(num,numch)

for{
for _,v:=range file{
fmt.Println(v,<-numch)
}
fmt.Println("------------")
time.Sleep(1e9*3)
}

}
func getNum(num []int,numch chan int) {
for{
for _,y:=range num{
numch<-y
}
var x int
for k,v:= range num{
if k==0{
x=v
continue
}
num[k-1]=v
}
num[3]=x
}
}

我也写一个,优雅不优雅就不知道了.
输出如下:
A 1
B 2
C 3
D 4


--------

A 2
B 3
C 4
D 1


--------

A 3
B 4
C 1
D 2


-------


A 4
B 1
C 2
D 3
循环输出

要回复问题请先登录注册