英文:
Golang: why following code snippet do not write to file?
问题
我有以下一段代码,但它没有将任何数据写入到log.txt文件中。我不明白为什么会这样?这不应该是同步问题,因为我在启动任何go例程之前都关闭了文件,并在每个例程内部打开/关闭文件。
package main
import (
"fmt"
"runtime"
"os"
"time"
)
func main() {
runtime.GOMAXPROCS(4)
f, _ := os.Create("./log.txt")
f.Close()
logCh := make(chan string, 50)
go func() {
for {
msg, ok := <- logCh
if ok {
logTime := time.Now().Format(time.RFC3339)
f, _ := os.OpenFile("./log.txt", os.O_APPEND, os.ModeAppend)
f.WriteString(logTime + " - " + msg)
f.Close()
} else {
break
}
}
}()
for i:=1; i < 10;i++ {
for j:=1; j<10;j++ {
go func(i, j int) {
msg := fmt.Sprintf("%d + %d = %d\n", i, j, i+j)
logCh <- msg
fmt.Print(msg)
}(i, j)
}
}
//fmt.Scanln()
}
英文:
I have following part of code which do not write any data to file log.txt. I don't understand why ? It should not be sync problem, because I close file before start any go routine and open/close file inside of each routine.
package main
import (
"fmt"
"runtime"
"os"
"time"
)
func main() {
runtime.GOMAXPROCS(4)
f, _ := os.Create("./log.txt")
f.Close()
logCh := make(chan string, 50)
go func() {
for {
msg, ok := <- logCh
if ok {
logTime := time.Now().Format(time.RFC3339)
f, _ := os.OpenFile("./log.txt", os.O_APPEND, os.ModeAppend)
f.WriteString(logTime + " - " + msg)
f.Close()
} else {
break
}
}
}()
for i:=1; i < 10;i++ {
for j:=1; j<10;j++ {
go func(i, j int) {
msg := fmt.Sprintf("%d + %d = %d\n", i, j, i+j)
logCh <- msg
fmt.Print(msg)
}(i, j)
}
}
//fmt.Scanln()
}
答案1
得分: 2
两个明显的问题:
-
主程序没有等待其他goroutine,当主程序返回时,程序终止,这就是为什么log.txt是空的。可以使用
sync.WaitGroup
来解决这个问题。 -
msg, ok := <- logCh
,只有当logCh
被关闭且为空时,ok
才为false
。而你没有调用close(logCh)
。
英文:
two obvious faults:
-
the main routine do not wait for other goroutines, when main routine return, the program terminate, that's why log.txt is empty.
sync.WaitGroup
maybe helpful. -
msg, ok := <- logCh
,ok
is onlyfalse
whenlogCh
is closed and empty. And you are not callingclose(logCh)
.
答案2
得分: 1
首先,你需要等待通道为空。在这种情况下,你也不需要使用缓冲通道。可以使用WaitGroup
。
其次,每个goroutine中打开和关闭文件并忽略错误是实际的问题。你不需要每次都打开和关闭文件。只需打开一次,写入后进行同步。
以下是修正后的代码:
package main
import (
"fmt"
"os"
"runtime"
"sync"
"time"
)
func main() {
runtime.GOMAXPROCS(4)
f, _ := os.Create("./log.txt")
defer f.Close()
logCh := make(chan string)
var wg sync.WaitGroup
for i := 1; i < 10; i++ {
for j := 1; j < 10; j++ {
wg.Add(1)
go func(i, j int) {
defer wg.Done()
msg := fmt.Sprintf("%d + %d = %d\n", i, j, i+j)
logCh <- msg
fmt.Print(msg)
}(i, j)
}
}
go func() {
for {
msg, ok := <-logCh
if ok {
logTime := time.Now().Format(time.RFC3339)
f.WriteString(logTime + " - " + msg)
f.Sync()
} else {
break
}
}
}()
wg.Wait()
//fmt.Scanln()
}
在这个问题中还有一些额外的信息。
英文:
For one, you need to wait for your channel to empty. In this case you don't need a buffered channel either. Use a WaitGroup
Secondly, opening and closing the file in every goroutine while ignoring the error is the actual issue. You don't need to open and close the file every time. Open once, sync after writes.
This works:
package main
import (
"fmt"
"os"
"runtime"
"sync"
"time"
)
func main() {
runtime.GOMAXPROCS(4)
f, _ := os.Create("./log.txt")
defer f.Close()
logCh := make(chan string)
var wg sync.WaitGroup
for i := 1; i < 10; i++ {
for j := 1; j < 10; j++ {
wg.Add(1)
go func(i, j int) {
defer wg.Done()
msg := fmt.Sprintf("%d + %d = %d\n", i, j, i+j)
logCh <- msg
fmt.Print(msg)
}(i, j)
}
}
go func() {
for {
msg, ok := <-logCh
if ok {
logTime := time.Now().Format(time.RFC3339)
f.WriteString(logTime + " - " + msg)
f.Sync()
} else {
break
}
}
}()
wg.Wait()
//fmt.Scanln()
}
There's also some extra info in this question
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论