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 如何实现?大牛们请上代码

已邀请:

tom0001

赞同来自: johney haoxiong fanyang nbsword solar

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 - 程序员

赞同来自: 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)吗?

不够优雅

hmly

赞同来自: fanyang

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

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)
}

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 - 既要有梦想,又要有实力

赞同来自:

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

jdlau - https://www.jdscript.com/

赞同来自:

我的版本:

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 循环输出

hxzqlh

赞同来自:

参考了一楼实现,正宗的解答:

package main

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

const NUM = 4

var outfile [NUM]*os.File

func main() {
    cha := make(chan struct{})
    chb := make(chan struct{})
    chc := make(chan struct{})
    chd := make(chan struct{})

    for i := 0; i < NUM; i++ {
        outfile[i], _ = os.Create(fmt.Sprintf("outfile_%d", (i + 1)))
    }

    go test(1, 0, cha, chb) // 0 ---> 3
    go test(2, 1, chb, chc) // 1 ---> 0
    go test(3, 2, chc, chd) // 2 ---> 1
    go test(4, 3, chd, cha) // 3 ---> 2

    cha <- struct{}{}
    time.Sleep(time.Second)
}

func test(i int, begIndex int, ch1, ch2 chan struct{}) {
    var nextFileIndex = begIndex
    for range ch1 {
        outfile[nextFileIndex].WriteString(fmt.Sprintf("%d ", i))
        nextFileIndex = (nextFileIndex - 1 + NUM) % NUM
        ch2 <- struct{}{}
    }
}

TevicTT

赞同来自:

每个线程负责从自己任务队列中取任务,做完后同时发一个新任务到后续线程的任务队列中

package main

import (
    "fmt"
    "sync"
)

func main() {
    tC := []chan int{make(chan int, 1), make(chan int, 1), make(chan int, 1), make(chan int, 1)}
    for i := 0; i < 4; i++ {
        tC[i] <- i
    }
    files := [][]int{[]int{}, []int{}, []int{}, []int{}}
    var wg sync.WaitGroup
    wg.Add(4)
    threads := func(tIdx int) {
        defer wg.Done()
        for i := 0; i < 20; i++ {
            fIdx := <-tC[tIdx]
            files[fIdx] = append(files[fIdx], tIdx+1)
            tC[(tIdx+1)%4] <- fIdx
        }
    }
    for i := 0; i < 4; i++ {
        go threads(i)
    }
    wg.Wait()
    for i := 0; i < len(files); i++ {
        fmt.Println(files[i])
    }
}

lvpengzhen

赞同来自:

4个runFunc 执行write动作写自己的num,runMaster负责调度handle任务。


import (
    "fmt"
    slog "log"
    "os"
    "time"
)

var mylog *slog.Logger = slog.New(os.Stdout, "", slog.LstdFlags|slog.Lshortfile)

type handle interface {
    write(int)
}
type wFile struct {
    f *os.File
}

var (
    AFile *wFile = NewFile("./a.txt")
    BFile *wFile = NewFile("./b.txt")
    CFile *wFile = NewFile("./c.txt")
    DFile *wFile = NewFile("./d.txt")
)

func NewFile(path string) *wFile {
    wfile := new(wFile)
    file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
    if err != nil {
        mylog.Panicln(err)
        return nil
    }
    wfile.f = file
    return wfile
}

func (self *wFile) write(i int) {
    str := fmt.Sprintf("%d ", i)
    mylog.Println(str)
    self.f.WriteString(str)
}

func runFunc(i int, ch []chan handle) {
    for {
        handle := <-ch[i]
        handle.write(i + 1)
    }
}

func runMaster(chs []chan handle) {
    for {
        for i := 0; i < 4; i++ {
            chs[i] <- AFile
            chs[(i+1)%4] <- BFile
            chs[(i+2)%4] <- CFile
            chs[(i+3)%4] <- DFile
        }
    }
}

func main() {

    chs := make([]chan handle, 4)

    for i := 0; i < 4; i++ {
        chs[i] = make(chan handle)
    }
    for i := 0; i < 4; i++ {
        go runFunc(i, chs)
    }

    go runMaster(chs)

    time.Sleep(30 * time.Second)

}

TiNiT

赞同来自:

func main() {
    chs := make([]chan int, 4)
    files := make([]string, 4)
    chFiles := make([]chan string, 4)
    write := func(i int, chFirst, chSecond chan string) {
        for {
            select {
            case path := <-chFirst:
                fmt.Println("write<"+strconv.Itoa(i)+">to<"+path+">")
                file, _ := os.OpenFile(path,os.O_WRONLY,0644)
                n,_ := file.Seek(0,os.SEEK_END)
                file.WriteAt([]byte(strconv.Itoa(i)),n)
                file.Close()
                go func(){chSecond <- path}()
            }
        }
    }

    for i := 0; i < 4; i++ {
        chs[i] = make(chan int)
        path := filepath.Join("C:/", string(rune(i+65))+".txt")
        os.Create(path)
        files[i] = path
        chFiles[i] = make(chan string)
    }

    for i := 1; i < 5; i++ {
        go write(i, chFiles[i-1], chFiles[i%4])
    }

    for i := 0; i < 4; i++ {
        chFiles[i] <- files[i]
    }

    time.Sleep(time.Second * 10)
}

xianghanhuang

赞同来自:

看了一堆都是自己调度的。能不能有点新思路,其实不需要什么调度,也不用什么chan。 4个线程可以实现很简单的就是写入文件动作就可以了,主要是分写入区域来实现。仔细观察每个线程负责输出的位置间隔都是固定的,例如线程1 在文件 A 中是 1xxx1xxx1xxx1xxx1,线程2在文件A是x2xxx2xxx2xxx2.我们只要把线程写入的分好区域就不会冲突了

package main

import (
    "sync"
    "os"
    "time"
)

type syncFile struct {
    l    sync.Mutex
    file *os.File
}

type fileWriter struct {
    writeVal     byte
    startIndexes []int64
    files        []*syncFile
    stopl        sync.Mutex
    stop         bool
}

func (self *fileWriter) Stop() {
    self.stopl.Lock()
    self.stop = true
    self.stopl.Unlock()
}

func (self *fileWriter) mustStop() (v bool) {
    self.stopl.Lock()
    v = self.stop
    self.stopl.Unlock()
    return
}

func (self *fileWriter) startWrite() {
    var i int
    fileCount := len(self.files)
    for !self.mustStop() {
        f := self.files[i]
        f.l.Lock()
        //分区域写入文件中,和其他线程互不干扰
        f.file.WriteAt([]byte{self.writeVal}, self.startIndexes[i])
        f.l.Unlock()
        self.startIndexes[i] += int64(fileCount)
        i = (i + 1) % fileCount
    }
}

func main() {

    fileA,_ := os.Create("C:/goapp/win64/a.txt")
    fileB,_ := os.Create("C:/goapp/win64/b.txt")
    fileC,_ := os.Create("C:/goapp/win64/c.txt")
    fileD,_ := os.Create("C:/goapp/win64/d.txt")

    files := []*syncFile{
        &syncFile{ file:fileA },
        &syncFile{ file:fileB },
        &syncFile{ file:fileC },
        &syncFile{ file:fileD },
    }

    t1 := &fileWriter{
        writeVal:'1',
        startIndexes:[]int64{0,3,2,1}, //线程1 在A文件的起始位置是0,在B文件的起始位置是3,C文件中是2,D文件中是 1
        files:files ,
    }

    t2 := &fileWriter{
        writeVal:'2',
        startIndexes:[]int64{1,0,3,2},
        files:files ,
    }

    t3 := &fileWriter{
        writeVal:'3',
        startIndexes:[]int64{2,1,0,3},
        files:files ,
    }

    t4 := &fileWriter{
        writeVal:'4',
        startIndexes:[]int64{3,2,1,0},
        files:files ,
    }

    go t1.startWrite()
    go t2.startWrite()
    go t3.startWrite()
    go t4.startWrite()

    time.Sleep( time.Second * 10 )

    t1.Stop()
    t2.Stop()
    t3.Stop()
    t3.Stop()
    fileA.Close()
    fileB.Close()
    fileC.Close()
    fileD.Close()

}

etabestX - gopher

赞同来自:

package main

import (
    "os"
    "strconv"
    "sync"
)

var sw sync.WaitGroup

var fChan [4]chan struct{}
var fs [4]*os.File

func writeFile(index int, content string) int {
    _, err := fs[index].WriteString(content)
    if err != nil {
        panic(err.Error())
    }
    fChan[index] <- struct{}{}
    var res int
    if index > 0 {
        res = index - 1
    } else {
        res = 3
    }
    return res
}

func product(index int) {
    value := strconv.Itoa(index + 1)
    res := writeFile(index, value)
    for i := 0; i < 11; i++ {
        <-fChan[res]
        res = writeFile(res, value)
    }
    sw.Done()
}

func main() {

    for k := range fChan {
        fChan[k] = make(chan struct{}, 1)
    }
    var err error
    fs[0], err = os.OpenFile("file/A", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        panic(err.Error())
    }
    defer fs[0].Close()
    fs[1], err = os.OpenFile("file/B", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        panic(err.Error())
    }
    defer fs[1].Close()
    fs[2], err = os.OpenFile("file/C", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        panic(err.Error())
    }
    defer fs[2].Close()
    fs[3], err = os.OpenFile("file/D", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        panic(err.Error())
    }
    defer fs[3].Close()
    for i := 0; i < 4; i++ {
        sw.Add(1)
        go product(i)
    }
    sw.Wait()
}

xianghanhuang

赞同来自:

不需要用到channel,4条线程直接对文件输出,顺序不会乱。代码也就20~30行。

package main

import (
    "sync"
    "os"
    "time"
)

func main() {

    var (
        goCount   = 4
        fileNames = []string{"C:/goapp/win64/a.txt", "C:/goapp/win64/b.txt", "C:/goapp/win64/c.txt", "C:/goapp/win64/d.txt"}
        files     = make([]*os.File, len(fileNames))
        fileLocks = make([]*sync.Mutex, len(fileNames))
        err       error
    )

    for i, fn := range fileNames {
        files[i], err = os.Create(fn)
        if err != nil {
            panic(err)
        }
        fileLocks[i] = &sync.Mutex{}
    }

    for i := 0; i < goCount; i++ {
        go func(goId int, val []byte) {

            i := 0
            inc := int64(goCount * len(val))
            wsiLen := len(fileNames)
            wsi := make([]int64, wsiLen)

            for j := 0; j < wsiLen; j++ {
                wsi[j] = int64(goId)
                if goId == 0 {
                    goId = wsiLen - 1
                } else {
                    goId--
                }
            }

            for {
                fileLocks[i].Lock()
                _, err := files[i].WriteAt(val, wsi[i])
                if err != nil {
                    break
                }
                fileLocks[i].Unlock()
                wsi[i] += inc
                i = (i + 1) % goCount
            }

        }(i, []byte{byte(i + '1')})
    }

    time.Sleep(time.Second * 10)
    for _, f := range files {
        f.Close()
    }

}

要回复问题请先登录注册