在Golang循环中的并行性

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

parallelism in Golang loop

问题

我有一个项目,需要在CPU的多个核心上运行它以获得更快的速度。我在Fortran中使用了omplib,但对于Golang的并行性不太熟悉。我尝试了goroutines,但出现了问题,导致结果错误。这是我的代码:

  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "log"
  6. "math"
  7. "math/rand"
  8. "os"
  9. "time"
  10. )
  11. const (
  12. n_particles int = 2048
  13. n_steps int = 1000000
  14. dt float64 = 1.0
  15. v0 float64 = 0.50
  16. radius float64 = 1.0
  17. f_intensity float64 = 1.8
  18. scale float64 = 32.0
  19. alpha float64 = 1.0 / 36.0
  20. )
  21. var (
  22. x [n_particles + 1]float64
  23. y [n_particles + 1]float64
  24. angles [n_particles + 1]float64
  25. vx [n_particles + 1]float64
  26. vy [n_particles + 1]float64
  27. order [n_steps + 1]float64
  28. )
  29. func main() {
  30. /////randomizer
  31. vstart := time.Now()
  32. rsource := rand.NewSource(time.Now().UnixNano())
  33. randomizer := rand.New(rsource)
  34. for i := 0; i <= n_particles; i++ {
  35. x[i] = (randomizer.Float64()) * scale
  36. y[i] = (randomizer.Float64()) * scale
  37. angles[i] = (randomizer.Float64()) * math.Pi * 2
  38. sin, cos := math.Sincos(angles[i])
  39. vx[i] = v0 * cos
  40. vy[i] = v0 * sin
  41. }
  42. //////main loop
  43. for i := 0; i <= n_steps; i++ {
  44. start := time.Now()
  45. for j := 0; j <= n_particles; j++ {
  46. x[j] = x[j] + (vx[j] * dt)
  47. //x[j] = math.Mod(x[j], scale)
  48. if x[j] < 0.0 {
  49. x[j] = x[j] + scale
  50. }
  51. if x[j] >= scale {
  52. x[j] = x[j] - scale
  53. }
  54. y[j] = y[j] + (vy[j] * dt)
  55. //y[j] = math.Mod(x[j], scale)
  56. if y[j] < 0.0 {
  57. y[j] = y[j] + scale
  58. }
  59. if y[j] >= scale {
  60. y[j] = y[j] - scale
  61. }
  62. }
  63. type intpos struct {
  64. x, y int64
  65. }
  66. adjacencyIndex := make(map[intpos][]int)
  67. ////getting each boxes particles
  68. for j := 0; j <= n_particles; j++ {
  69. // . . .
  70. ix, iy := int64(math.Floor(x[j])), int64(math.Floor(y[j])) // getting particle box
  71. adjacencyIndex[intpos{ix, iy}] = append(adjacencyIndex[intpos{ix, iy}], j) // adding particles to boxes
  72. }
  73. /////////
  74. m_angles := angles
  75. ////particle loop - I WANT FOLLOWING LOOP PARALLEL
  76. for j := 0; j <= n_particles; j++ {
  77. sumanglesx := 0.0
  78. sumanglesy := 0.0
  79. ix, iy := int64(math.Floor(x[j])), int64(math.Floor(y[j]))
  80. // fxi = math.Floor(x[j])
  81. // fyi = math.Floor(y[j])
  82. for dx := -1; dx <= 1; dx++ {
  83. for dy := -1; dy <= 1; dy++ {
  84. adjacentParticles := adjacencyIndex[intpos{ix + int64(dx), iy + int64(dy)}]
  85. for _, k := range adjacentParticles {
  86. dist := ((x[k] - x[j]) * (x[k] - x[j])) + ((y[k] - y[j]) * (y[k] - y[j]))
  87. if dist < radius {
  88. sy, sx := math.Sincos(angles[k])
  89. if k <= j {
  90. sumanglesx = sumanglesx + sx
  91. sumanglesy = sumanglesy + sy
  92. } else {
  93. sx = alpha * sx
  94. sy = alpha * sy
  95. sumanglesx = sumanglesx + sx
  96. sumanglesy = sumanglesy + sy
  97. }
  98. }
  99. }
  100. }
  101. }
  102. bsource := rand.NewSource(time.Now().UnixNano())
  103. bandomizer := rand.New(bsource)
  104. sumanglesy = sumanglesy
  105. sumanglesx = sumanglesx
  106. r_angles := math.Atan2(sumanglesy, sumanglesx)
  107. }
  108. }
  109. }

现在我想让以下循环并行运行:

  1. ////particle loop - I WANT FOLLOWING LOOP PARALLEL
  2. for j := 0; j <= n_particles; j++ {
  3. sumanglesx := 0.0
  4. sumanglesy := 0.0
  5. ix, iy := int64(math.Floor(x[j])), int64(math.Floor(y[j]))
  6. // fxi = math.Floor(x[j])
  7. // fyi = math.Floor(y[j])
  8. for dx := -1; dx <= 1; dx++ {
  9. for dy := -1; dy <= 1; dy++ {
  10. adjacentParticles := adjacencyIndex[intpos{ix + int64(dx), iy + int64(dy)}]
  11. for _, k := range adjacentParticles {
  12. dist := ((x[k] - x[j]) * (x[k] - x[j])) + ((y[k] - y[j]) * (y[k] - y[j]))
  13. if dist < radius {
  14. sy, sx := math.Sincos(angles[k])
  15. if k <= j {
  16. sumanglesx = sumanglesx + sx
  17. sumanglesy = sumanglesy + sy
  18. } else {
  19. sx = alpha * sx
  20. sy = alpha * sy
  21. sumanglesx = sumanglesx + sx
  22. sumanglesy = sumanglesy + sy
  23. }
  24. }
  25. }
  26. }
  27. }
  28. bsource := rand.NewSource(time.Now().UnixNano())
  29. bandomizer := rand.New(bsource)
  30. sumanglesy = sumanglesy
  31. sumanglesx = sumanglesx
  32. r_angles := math.Atan2(sumanglesy, sumanglesx)
  33. }

请注意,我已经在代码中用注释标记了要并行运行的循环部分。

英文:

I have a project and need to run it on multiple cores of an cpu to get more speed . I have used omplib in fortran but I am not familiar with Golang parallelism . I tried goroutines but that went wrong and made a mess and I got false results. This is my code :

  1. package main
  2. import (
  3. &quot;bufio&quot;
  4. &quot;fmt&quot;
  5. &quot;log&quot;
  6. &quot;math&quot;
  7. &quot;math/rand&quot;
  8. &quot;os&quot;
  9. &quot;time&quot;
  10. )
  11. const (
  12. n_particles int = 2048
  13. n_steps int = 1000000
  14. dt float64 = 1.0
  15. v0 float64 = 0.50
  16. radius float64 = 1.0
  17. f_intensity float64 = 1.8
  18. scale float64 = 32.0
  19. alpha float64 = 1.0 / 36.0
  20. )
  21. var (
  22. x [n_particles + 1]float64
  23. y [n_particles + 1]float64
  24. angles [n_particles + 1]float64
  25. vx [n_particles + 1]float64
  26. vy [n_particles + 1]float64
  27. order [n_steps + 1]float64
  28. )
  29. func main() {
  30. /////randomizer
  31. vstart := time.Now()
  32. rsource := rand.NewSource(time.Now().UnixNano())
  33. randomizer := rand.New(rsource)
  34. for i := 0; i &lt;= n_particles; i++ {
  35. x[i] = (randomizer.Float64()) * scale
  36. y[i] = (randomizer.Float64()) * scale
  37. angles[i] = (randomizer.Float64()) * math.Pi * 2
  38. sin, cos := math.Sincos(angles[i])
  39. vx[i] = v0 * cos
  40. vy[i] = v0 * sin
  41. }
  42. //////main loop
  43. for i := 0; i &lt;= n_steps; i++ {
  44. start := time.Now()
  45. for j := 0; j &lt;= n_particles; j++ {
  46. x[j] = x[j] + (vx[j] * dt)
  47. //x[j] = math.Mod(x[j], scale)
  48. if x[j] &lt; 0.0 {
  49. x[j] = x[j] + scale
  50. }
  51. if x[j] &gt;= scale {
  52. x[j] = x[j] - scale
  53. }
  54. y[j] = y[j] + (vy[j] * dt)
  55. //y[j] = math.Mod(x[j], scale)
  56. if y[j] &lt; 0.0 {
  57. y[j] = y[j] + scale
  58. }
  59. if y[j] &gt;= scale {
  60. y[j] = y[j] - scale
  61. }
  62. }
  63. type intpos struct {
  64. x, y int64
  65. }
  66. adjacencyIndex := make(map[intpos][]int)
  67. ////getting each boxes particles
  68. for j := 0; j &lt;= n_particles; j++ {
  69. // . . .
  70. ix, iy := int64(math.Floor(x[j])), int64(math.Floor(y[j])) // getting particle box
  71. adjacencyIndex[intpos{ix, iy}] = append(adjacencyIndex[intpos{ix, iy}], j) // adding particles to boxes
  72. }
  73. /////////
  74. m_angles := angles

Now I want following loop run in parallel :

  1. ////particle loop - I WANT FOLLOWING LOOP PARALLEL
  2. for j := 0; j &lt;= n_particles; j++ {
  3. sumanglesx := 0.0
  4. sumanglesy := 0.0
  5. ix, iy := int64(math.Floor(x[j])), int64(math.Floor(y[j]))
  6. // fxi = math.Floor(x[j])
  7. // fyi = math.Floor(y[j])
  8. for dx := -1; dx &lt;= 1; dx++ {
  9. for dy := -1; dy &lt;= 1; dy++ {
  10. adjacentParticles := adjacencyIndex[intpos{ix + int64(dx), iy + int64(dy)}]
  11. for _, k := range adjacentParticles {
  12. dist := ((x[k] - x[j]) * (x[k] - x[j])) + ((y[k] - y[j]) * (y[k] - y[j]))
  13. if dist &lt; radius {
  14. sy, sx := math.Sincos(angles[k])
  15. if k &lt;= j {
  16. sumanglesx = sumanglesx + sx
  17. sumanglesy = sumanglesy + sy
  18. } else {
  19. sx = alpha * sx
  20. sy = alpha * sy
  21. sumanglesx = sumanglesx + sx
  22. sumanglesy = sumanglesy + sy
  23. }
  24. }
  25. }
  26. }
  27. }
  28. bsource := rand.NewSource(time.Now().UnixNano())
  29. bandomizer := rand.New(bsource)
  30. sumanglesy = sumanglesy
  31. sumanglesx = sumanglesx
  32. r_angles := math.Atan2(sumanglesy, sumanglesx)
  33. }
  34. }
  35. }

I specified one loop which should run parallelly .

答案1

得分: 1

这里有两种尝试的方法:https://play.golang.org/p/O1uB2zzJEC5

我更喜欢使用通道的方法,因为对我来说更符合Go的习惯用法,并且可以更容易地处理panic、错误条件等。

英文:

Here are two approaches to try out: https://play.golang.org/p/O1uB2zzJEC5

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;sync&quot;
  5. )
  6. func main() {
  7. waitGroupApproach()
  8. channelApproach()
  9. }
  10. func waitGroupApproach() {
  11. fmt.Println(&quot;waitGroupApproach&quot;)
  12. var waitgroup sync.WaitGroup
  13. result_table := make([]int, 6, 6)
  14. for j := 0; j &lt;= 5; j++ {
  15. waitgroup.Add(1)
  16. go func(index int) {
  17. fmt.Println(index) // try putting here `j` instea of `index`
  18. result_table[index] = index*2
  19. waitgroup.Done()
  20. }(j) // you have to put any for-loop variables into closure
  21. // because otherwsie all routines inside will likely get the last j == n_particles + 1
  22. // as they will likely run after the loop has finished
  23. }
  24. fmt.Println(&quot;waiting&quot;)
  25. waitgroup.Wait()
  26. // process results further
  27. fmt.Println(&quot;finished&quot;)
  28. fmt.Println(result_table)
  29. }
  30. func channelApproach() {
  31. fmt.Println(&quot;\nchannelApproach&quot;)
  32. type intpos struct {
  33. x, y, index int
  34. }
  35. results := make(chan intpos)
  36. // initialize routines
  37. for j := 0; j &lt;= 5; j++ {
  38. go func(index int) {
  39. // do processing
  40. results &lt;- intpos{index*2, index*3, index}
  41. }(j)
  42. }
  43. fmt.Println(&quot;Waiting..&quot;)
  44. // collect results, iterate the same number of times
  45. result_table := make([]int, 6)
  46. for j := 0; j &lt;= 5; j++ {
  47. r := &lt;- results
  48. // watch out order, migth not be the same as in invocation,
  49. // so that&#39;s why I store j in results as well
  50. fmt.Println(r.index, r.x, r.y)
  51. result_table[r.index] = r.x
  52. }
  53. fmt.Println(&quot;Finished..&quot;)
  54. fmt.Println(result_table)
  55. }

I prefer the channel approach because it's more go idiomatic to me and it allows to easier handle panic, error conditions, etc.

huangapple
  • 本文由 发表于 2021年10月10日 19:51:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/69514900.html
匿名

发表评论

匿名网友

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

确定