在Go语言中的并行处理

huangapple go评论75阅读模式
英文:

Parallel processing in golang

问题

给定以下代码:

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    for i := 0; i < 3; i++ {
        go f(i)
    }

    // 防止主函数立即退出
    var input string
    fmt.Scanln(&input)
}

func f(n int) {
    for i := 0; i < 10; i++ {
        dowork(n, i)
        amt := time.Duration(rand.Intn(250))
        time.Sleep(time.Millisecond * amt)
    }
}

func dowork(goroutine, loopindex int) {
    // 模拟工作
    time.Sleep(time.Second * time.Duration(5))
    fmt.Printf("gr[%d]: i=%d\n", goroutine, loopindex)
}

我可以假设'dowork'函数将并行执行吗?

这是实现并行的正确方式吗?还是更好地使用通道和为每个goroutine分离'dowork'工作器?

英文:

Given the following code:

package main

import (
	&quot;fmt&quot;
	&quot;math/rand&quot;
	&quot;time&quot;
)

func main() {
	for i := 0; i &lt; 3; i++ {
		go f(i)
	}

	// prevent main from exiting immediately
	var input string
	fmt.Scanln(&amp;input)
}

func f(n int) {
	for i := 0; i &lt; 10; i++ {
		dowork(n, i)
		amt := time.Duration(rand.Intn(250))
		time.Sleep(time.Millisecond * amt)
	}
}

func dowork(goroutine, loopindex int) {
	// simulate work
	time.Sleep(time.Second * time.Duration(5))
	fmt.Printf(&quot;gr[%d]: i=%d\n&quot;, goroutine, loopindex)
}

Can i assume that the 'dowork' function will be executed in parallel?

Is this a correct way of achieving parallelism or is it better to use channels and separate 'dowork' workers for each goroutine?

答案1

得分: 30

关于GOMAXPROCS,你可以在Go 1.5的发布文档中找到相关信息:

默认情况下,Go程序的GOMAXPROCS设置为可用的核心数;在之前的版本中,默认值为1。

关于防止main函数立即退出,你可以利用WaitGroupWait函数。

我编写了这个实用函数来并行执行一组函数:

import "sync"

// Parallelize并行执行函数调用
func Parallelize(functions ...func()) {
    var waitGroup sync.WaitGroup
    waitGroup.Add(len(functions))

    defer waitGroup.Wait()

    for _, function := range functions {
        go func(copy func()) {
            defer waitGroup.Done()
            copy()
        }(function)
    }
}

所以在你的情况下,你可以这样做:

func1 := func() {
    f(0)
}

func2 := func() {
    f(1)
}

func3 := func() {
    f(2)
}

Parallelize(func1, func2, func3)

如果你想使用Parallelize函数,你可以在这里找到它:https://github.com/shomali11/util

英文:

Regarding GOMAXPROCS, you can find this in Go 1.5's release docs:

> By default, Go programs run with GOMAXPROCS set to the number of cores available; in prior releases it defaulted to 1.

Regarding preventing the main function from exiting immediately, you could leverage WaitGroup's Wait function.

I wrote this utility function to help parallelize a group of functions:

import &quot;sync&quot;

// Parallelize parallelizes the function calls
func Parallelize(functions ...func()) {
    var waitGroup sync.WaitGroup
    waitGroup.Add(len(functions))

	defer waitGroup.Wait()

	for _, function := range functions {
    	go func(copy func()) {
	    	defer waitGroup.Done()
		    copy()
	    }(function)
    }
}

So in your case, we could do this

func1 := func() {
    f(0)
}

func2 = func() {
    f(1)
}

func3 = func() {
    f(2)
}

Parallelize(func1, func2, func3)

If you wanted to use the Parallelize function, you can find it here https://github.com/shomali11/util

答案2

得分: 23

这个答案已经过时了。请参考这个答案


你的代码将以并发方式运行,但不会并行运行。你可以通过设置GOMAXPROCS来使其并行运行。

不太清楚你在这里尝试实现什么,但在我看来,这看起来是一种完全有效的并发实现方式。

英文:

This answer is outdated. Please see this answer instead.


Your code will run concurrently, but not in parallel. You can make it run in parallel by setting GOMAXPROCS.

It's not clear exactly what you're trying to accomplish here, but it looks like a perfectly valid way of achieving concurrency to me.

答案3

得分: 0

f()将被并发执行,但是每个f()内部的许多dowork()将按顺序执行。等待标准输入(stdin)并不是确保程序完成执行的正确方法。你必须创建一个通道(channel),每个f()在完成时向该通道推送一个true
main()的最后,你必须等待通道上的n个true。其中n是你创建的f()的数量。

英文:

f() will be executed concurrently but many dowork() will be executed sequentially within each f(). Waiting on stdin is also not the right way to ensure that your routines finished execution. You must spin up a channel that each f() pushes a true on when the f() finishes.
At the end of the main() you must wait for n number of true's on the channel. n being the number of f() that you have spun up.

答案4

得分: 0

这是我刚开始学习时帮助我的代码。

package main

import "fmt"

func put(number chan<- int, count int) {
    i := 0
    for ; i <= (5 * count); i++ {
        number <- i
    }
    number <- -1
}

func subs(number chan<- int) {
    i := 10
    for ; i <= 19; i++ {
        number <- i
    }
}

func main() {
    channel1 := make(chan int)
    channel2 := make(chan int)
    done := 0
    sum := 0

    go subs(channel2)
    go put(channel1, 1)
    go put(channel1, 2)
    go put(channel1, 3)
    go put(channel1, 4)
    go put(channel1, 5)

    for done != 5 {
        select {
        case elem := <-channel1:
            if elem < 0 {
                done++
            } else {
                sum += elem
                fmt.Println(sum)
            }
        case sub := <-channel2:
            sum -= sub
            fmt.Printf("atimta : %d\n", sub)
            fmt.Println(sum)
        }
    }
    close(channel1)
    close(channel2)
}

“传统的基于集群的系统(如超级计算机)使用MPI在处理器之间进行并行执行。MPI是在不同处理器上执行的操作系统实例之间的通信接口;它不支持其他进程操作,如调度。(为了进一步复杂化事情,因为MPI进程由操作系统执行,一个单独的处理器可以运行多个MPI进程和/或一个单独的MPI进程也可以执行多个线程!)”

英文:

This helped me when I was starting out.

	package main

	import &quot;fmt&quot;

	func put(number chan&lt;- int, count int) {
		i := 0
		for ; i &lt;= (5 * count); i++ {
			number &lt;- i
		}
		number &lt;- -1
	}

	func subs(number chan&lt;- int) {
		i := 10
		for ; i &lt;= 19; i++ {
			number &lt;- i
		}
	}

	func main() {
		channel1 := make(chan int)
		channel2 := make(chan int)
		done := 0
		sum := 0

		go subs(channel2)
		go put(channel1, 1)
		go put(channel1, 2)
		go put(channel1, 3)
		go put(channel1, 4)
		go put(channel1, 5)

		for done != 5 {
			select {
			case elem := &lt;-channel1:
				if elem &lt; 0 {
					done++
				} else {
					sum += elem
					fmt.Println(sum)
				}
			case sub := &lt;-channel2:
				sum -= sub
				fmt.Printf(&quot;atimta : %d\n&quot;, sub)
				fmt.Println(sum)
			}
		}
		close(channel1)
		close(channel2)
	}

"Conventional cluster-based systems (such as supercomputers) employ parallel execution between processors using MPI. MPI is a communication interface between processes that execute in operating system instances on different processors; it doesn't support other process operations such as scheduling. (At the risk of complicating things further, because MPI processes are executed by operating systems, a single processor can run multiple MPI processes and/or a single MPI process can also execute multiple threads!)"

答案5

得分: 0

你可以在最后添加一个循环,以阻塞直到任务完成:

package main
import "time"

func f(n int, b chan bool) {
   println(n)
   time.Sleep(time.Second)
   b <- true
}

func main() {
   b := make(chan bool, 9)
   for n := cap(b); n > 0; n-- {
      go f(n, b)
   }
   for <-b {
      if len(b) == 0 { break }
   }
}
英文:

You can add a loop at the end, to block until the jobs are done:

package main
import &quot;time&quot;

func f(n int, b chan bool) {
   println(n)
   time.Sleep(time.Second)
   b &lt;- true
}

func main() {
   b := make(chan bool, 9)
   for n := cap(b); n &gt; 0; n-- {
      go f(n, b)
   }
   for &lt;-b {
      if len(b) == 0 { break }
   }
}

huangapple
  • 本文由 发表于 2014年8月4日 00:06:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/25106526.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定