简体   繁体   English

如何在多个不同的控制台中制作 goroutines output?

[英]How to make goroutines output in multiple different consoles?

I am practicing using goroutines and found that if both goroutines are printing at the same time, it becomes difficult to read.我正在练习使用 goroutines,发现如果两个 goroutines 同时打印,就会变得难以阅读。

func main() {
    s1 := rand.NewSource(time.Now().UnixNano())
    r1 := rand.New(s1)
    wg := &sync.WaitGroup{}
    t1 := func(wg *sync.WaitGroup) {
        for i := 0; i < 100; i++ {
            time.Sleep(time.Microsecond * time.Duration(r1.Intn(100)))
            fmt.Println("T1 : ", i)
        }
        wg.Done()
    }
    t2 := func(wg *sync.WaitGroup) {
        for i := 0; i < 100; i++ {
            time.Sleep(time.Microsecond * time.Duration(r1.Intn(100)))
            fmt.Println("T2 : ", i)
        }
        wg.Done()
    }
    wg.Add(2)
    go t1(wg)
    go t2(wg)
    wg.Wait()
}

Output: Output:

T1 :  0
T2 :  0
T2 :  1
T1 :  1
T1 :  2
T2 :  2
T1 :  3
T2 :  3
T1 :  4
T2 :  4
T1 :  5
T2 :  5
T1 :  6
T2 :  6
T2 :  7
T1 :  7
T2 :  8
T1 :  8
T1 :  9
T2 :  9
T2 :  10
T1 :  10
......

Is there any way to open multiple consoles and let two goroutines output in different consoles?有什么办法可以打开多个控制台,让两个goroutines output 在不同的控制台?

  1. You may use a simple TCP terminal server - first run this TCP terminal server and you don't need to close it as long as you need ( or just use Netcat Command : nc -l 8080 then goto #2 and write to this TCP connection eg "127.0.0.1:8080"):你可以使用一个简单的TCP 终端服务器- 首先运行这个 TCP 终端服务器,你不需要关闭它,只要你需要(或者只使用Netcat 命令nc -l 8080然后转到 #2 并写入这个 ZB16399EF5F6A06D例如“127.0.0.1:8080”):
package main

import (
    "io"
    "log"
    "net"
    "os"
)

func main() {
    ln, err := net.Listen("tcp", "127.0.0.1:8080")
    if err != nil {
        log.Fatal(err)
    }
    for {
        w1, err := ln.Accept()
        if err != nil {
            log.Fatal(err)
        }
        io.Copy(os.Stdout, w1)
        w1.Close()
    }
}
  1. Then add this to your code:然后将其添加到您的代码中:
    w1, err := net.Dial("tcp", "127.0.0.1:8080")
    if err != nil {
        log.Fatal(err)
    }
    defer w1.Close()
  1. Then use w1 as your another io.Writer in your code eg fmt.Fprintln(w1, "T1: ", i) , an example:然后在代码中使用w1作为另一个io.Writer例如fmt.Fprintln(w1, "T1: ", i) ,例如:
package main

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

func main() {
    w1, err := net.Dial("tcp", "127.0.0.1:8080")
    if err != nil {
        log.Fatal(err)
    }
    defer w1.Close()

    // your code:
    s1 := rand.NewSource(time.Now().UnixNano())
    r1 := rand.New(s1)
    wg := &sync.WaitGroup{}
    t1 := func(wg *sync.WaitGroup) {
        for i := 0; i < 100; i++ {
            time.Sleep(time.Microsecond * time.Duration(r1.Intn(100)))
            fmt.Fprintln(w1, "T1 : ", i)
        }
        wg.Done()
    }
    t2 := func(wg *sync.WaitGroup) {
        for i := 0; i < 100; i++ {
            time.Sleep(time.Microsecond * time.Duration(r1.Intn(100)))
            fmt.Println("T2 : ", i)
        }
        wg.Done()
    }
    wg.Add(2)
    go t1(wg)
    go t2(wg)
    wg.Wait()
}

fmt.Print*(...) functions are wrappers for fmt.Fprint*(os.Stdout, ...) . fmt.Print*(...)函数是fmt.Fprint*(os.Stdout, ...)的包装器。 If you want to make two goroutines write to distinct writers, one first step in your code is to provide the writer they should use:如果你想让两个 goroutine 写入不同的 writer,代码中的第一步是提供他们应该使用的 writer:

    t1 := func(wg *sync.WaitGroup, out io.Writer) {
        for i := 0; i < 100; i++ {
            time.Sleep(time.Microsecond * time.Duration(r1.Intn(100)))
            fmt.Fprintln(out, "T1 : ", i)
        }
        wg.Done()
    }

    ...

    // for starters : keep using the same os.Stdout writer
    go t1(wg, os.Stdout)

Instead of a raw io.Writer , you may want to pass something to which you can log;您可能想要传递可以记录的内容,而不是原始io.Writer the standard library has the log.Logger struct:标准库有log.Logger结构:

    t1 := func(wg *sync.WaitGroup, l *log.Logger) {
        for i := 0; i < 100; i++ {
            time.Sleep(time.Microsecond * time.Duration(r1.Intn(100)))
            l.Println(i)
        }
        wg.Done()
    }

    ...

    // all logging libraries will allow you to specify some option which you can tune :
    l1 := log.New(os.Stdout, "T1 : ", log.Ltime) // will prefix all messages with "[time] T1 : "
    go t1(wg, l1)

    // this allows you to write :
    l2 := log.New(os.Stdout, "T2 : ", log.Ltime) // will prefix all messages with "[time] T2 : "
    go t2(wg, l2)

You may look into golang logging libraries for more features -- don't spend too much time on choosing a logging framework for a quick throwaway project, though.您可以查看 golang 日志库以获取更多功能——不过,不要花太多时间为快速一次性项目选择日志框架。


Now that you have an explicit way to pass two distinct writers (or loggers) to your goroutines, choose whatever suits your need to write to:既然您有一种明确的方式将两个不同的写入器(或记录器)传递给您的 goroutine,请选择适合您需要写入的任何内容:

  • have goroutine 1 log to Stdout and goroutine 2 log to Stderr让 goroutine 1 记录到 Stdout,goroutine 2 记录到 Stderr
  • log to file1 and file2 -- just run tail -f file2 in some separate terminal to get a "live view" of the output登录到file1file2 - 只需在某个单独的终端中运行tail -f file2即可获得 output 的“实时视图”
  • io.Discard is a golang built-in equivalent of /dev/null io.Discard是 golang 内置等效于/dev/null
  • log to a named pipe, a unix socket, a tcp connection...登录到一个名为 pipe、一个 unix 插座、一个 tcp 连接...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM