英文:
goroutine or multithreading is not working in golang
问题
我正在尝试在Go语言中实现多线程。我能够实现goroutine,但它的工作结果与预期不符。以下是我准备的示例程序:
func test(s string, fo *os.File) {
var s1 [105]int
count := 0
for x := 1000; x < 1101; x++ {
s1[count] = x
count++
}
for i := range s1 {
runtime.Gosched()
sd := s + strconv.Itoa(i)
var fileMutex sync.Mutex
fileMutex.Lock()
fmt.Fprintf(fo, sd)
defer fileMutex.Unlock()
}
}
func main() {
fo, err := os.Create("D:/Output.txt")
if err != nil {
panic(err)
}
for i := 0; i < 4; i++ {
go test("bye", fo)
}
}
输出结果为:good0bye0bye0bye0bye0good1bye1bye1bye1bye1good2bye2bye2bye2bye2...等等。
上述程序将创建一个文件,并在文件中写入"Hello"和"bye"。
我的问题是,我想创建5个线程,并希望使用不同的线程处理不同的值。如果你看上面的示例,它会打印4次"bye"。
我希望的输出结果是使用5个线程,如下所示:
good0bye0good1bye1good2bye2...等等。
你有什么办法可以实现这个要求吗?
英文:
I was trying to implement multithreading in golang. I am able to implement go routines but it is not working as expected. below is the sample program which i have prepared,
func test(s string, fo *os.File) {
var s1 [105]int
count :=0
for x :=1000; x<1101;x++ {
s1[count] = x;
count++
}
//fmt.Println(s1[0])
for i := range s1 {
runtime.Gosched()
sd := s + strconv.Itoa(i)
var fileMutex sync.Mutex
fileMutex.Lock()
fmt.Fprintf(fo,sd)
defer fileMutex.Unlock()
}
}
func main() {
fo,err :=os.Create("D:/Output.txt")
if err != nil {
panic(err)
}
for i := 0; i < 4; i++ {
go test("bye",fo)
}
}
OUTPUT - good0bye0bye0bye0bye0good1bye1bye1bye1bye1good2bye2bye2bye2bye2.... etc.
the above program will create a file and write "Hello" and "bye" in the file.
My problem is i am trying to create 5 thread and wanted to process different values values with different thread. if you will see the above example it is printing "bye" 4 times.
i wanted output like below using 5 thread,
good0bye0good1bye1good2bye2....etc....
any idea how can i achieve this?
答案1
得分: 3
首先,你需要在主函数中阻塞,直到所有其他goroutine返回。你程序中的互斥锁没有阻塞任何东西,而且由于它们在每次循环中重新初始化,它们甚至不会在自己的goroutine中阻塞。如果你不是从函数中返回,就不能延迟解锁,你需要在每次循环迭代中显式解锁。你没有使用数组中的任何值(尽管你应该使用切片),所以我们可以完全删除它。在一个行为良好的程序中,你也不需要runtime.GoSched
,它在这里没有任何作用。
一个等效的可以完整运行的程序如下:
var wg sync.WaitGroup
var fileMutex sync.Mutex
func test(s string, fo *os.File) {
defer wg.Done()
for i := 0; i < 105; i++ {
fileMutex.Lock()
fmt.Fprintf(fo, "%s%d", s, i)
fileMutex.Unlock()
}
}
func main() {
fo, err := os.Create("D:/output.txt")
if err != nil {
log.Fatal(err)
}
for i := 0; i < 4; i++ {
wg.Add(1)
go test("bye", fo)
}
wg.Wait()
}
最后,没有理由尝试从多个goroutine向单个文件写入连续的值,这样做效率更低。如果你希望整个文件中的值有序,你仍然需要使用单个goroutine。
英文:
First, you need to block in your main function until all other goroutines return. The mutexes in your program aren't blocking anything, and since they're re-initialized in each loop, they don't even block within their own goroutine. You can't defer an unlock if you're not returning from the function, you need to explicitly unlock in each iteration of the loop. You aren't using any of the values in your array (though you should use a slice instead), so we can drop that entirely. You also don't need runtime.GoSched
in a well-behaved program, and it does nothing here.
An equivalent program that will run to completion would look like:
var wg sync.WaitGroup
var fileMutex sync.Mutex
func test(s string, fo *os.File) {
defer wg.Done()
for i := 0; i < 105; i++ {
fileMutex.Lock()
fmt.Fprintf(fo, "%s%d", s, i)
fileMutex.Unlock()
}
}
func main() {
fo, err := os.Create("D:/output.txt")
if err != nil {
log.Fatal(err)
}
for i := 0; i < 4; i++ {
wg.Add(1)
go test("bye", fo)
}
wg.Wait()
}
Finally though, there's no reason to try and write serial values to a single file from multiple goroutines, and it's less efficient to do so. If you want the values ordered over the entire file, you will need to use a single goroutine anyway.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论