并发

并发性意味着应用程序同时(并发地)处理多个任务。
如果计算机只有一个CPU,应用程序可能不会在同一时间处理多个任务,但是在应用程序内一次处理多个任务。
在开始下一个任务之前,它不会完全完成一个任务。相反,CPU在不同的任务之间切换,直到任务完成。

即使只有一个线程在其中运行,也可以有一个并发应用程序。

并行

并行性意味着应用程序将其任务分割成更小的子任务,这些子任务可以并行处理,例如在多个cpu上同时处理。

为了实现真正的并行,您的应用程序必须有多个线程在运行,或者至少能够调度任务在其他线程、进程、cpu、显卡等中执行。

栗子:
你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。
你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。
你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。

image.png image.png
并发 并行

代码模拟使用咖啡机

Erlang 之父 Joe Armstrong 用一张5岁小孩都能看懂的图解释了并发与并行的区别
image.png

  • 并发 是两个队列 交替 使用 一台 咖啡机
  • 并行 是两个队列 同时 使用 两台 咖啡机

如果串行,一个队列使用一台咖啡机,那么哪怕前面那个人便秘了去厕所呆半天,后面的人也只能死等着他回来才能去接咖啡,这效率无疑是最低的

串行使用咖啡机

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. var (
  7. ListA = []string{"小明", "小红", "小王", "宝宝", "娜娜", "拉拉", "琪琪"}
  8. ListB = []string{"威廉", "巴克", "查理", "哈利", "哈瑞", "米菲", "珍妮", "米奇"}
  9. )
  10. func task(list []string, from string) {
  11. i := 0
  12. for {
  13. if (i >= len(list)) {
  14. if (from == "A") {
  15. fmt.Println("A队人员已排队完~~~")
  16. } else if (from == "B") {
  17. fmt.Println( "B队人员已排队完~~~")
  18. }
  19. break;
  20. }
  21. if (from == "A") {
  22. fmt.Printf("A队[%d]: %s 使用咖啡机 \n", i+1, list[i])
  23. } else if (from == "B") {
  24. fmt.Printf("B队[%d]: %s 使用咖啡机 \n", i+1, list[i])
  25. }
  26. i++;
  27. time.Sleep(time.Second)
  28. }
  29. }
  30. func main() {
  31. task(ListA, "A")
  32. task(ListB, "B")
  33. // 主协程
  34. for {
  35. ;
  36. }
  37. /**
  38. A队[1]: 小明 使用咖啡机
  39. A队[2]: 小红 使用咖啡机
  40. A队[3]: 小王 使用咖啡机
  41. A队[4]: 宝宝 使用咖啡机
  42. A队[5]: 娜娜 使用咖啡机
  43. A队[6]: 拉拉 使用咖啡机
  44. A队[7]: 琪琪 使用咖啡机
  45. A队人员已排队完~~~
  46. B队[1]: 威廉 使用咖啡机
  47. B队[2]: 巴克 使用咖啡机
  48. B队[3]: 查理 使用咖啡机
  49. B队[4]: 哈利 使用咖啡机
  50. B队[5]: 哈瑞 使用咖啡机
  51. B队[6]: 米菲 使用咖啡机
  52. B队[7]: 珍妮 使用咖啡机
  53. B队[8]: 米奇 使用咖啡机
  54. B队人员已排队完~~~
  55. */
  56. }

并发使用一台咖啡机

可能会遇见如下情况:

  1. A 队列被 B队列小伙伴插队了,这就是条件竞争

  2. A 队列有一位英俊小伙和 B 队列一位女神并排,轮到他们俩的时候两人互看对方一眼,互让一步同时彬彬有礼的说了一句:你先。这个时候活锁出现了。

  3. B 队列一位小伙伴,是代替其他朋友来打咖啡,他带了一箱子杯子,终于轮到他了。这时饥饿就出现了。

  4. A 队列一位小伙伴喜欢摩卡,卡布奇诺混合咖啡,B 队列一位小伙伴喜欢拿铁,摩卡混合咖啡。当他们互相等待对方摩卡出杯的时候后,死锁来了。 ```go package main

import ( “fmt” “time” )

var ( ListA = []string{“小明”, “小红”, “小王”, “宝宝”, “娜娜”, “拉拉”, “琪琪”} ListB = []string{“威廉”, “巴克”, “查理”, “哈利”, “哈瑞”, “米菲”, “珍妮”, “米奇”} )

func task(list []string, from string) { i := 0 for { if (i >= len(list)) { if (from == “A”) { fmt.Println(“A队人员已排队完~”) } else if (from == “B”) { fmt.Println( “B队人员已排队完~”) } break; } if (from == “A”) { fmt.Printf(“A队[%d]: %s 使用咖啡机 \n”, i+1, list[i]) } else if (from == “B”) { fmt.Printf(“B队[%d]: %s 使用咖啡机 \n”, i+1, list[i]) } i++; time.Sleep(time.Second) } }

func main() { // 子协程 go task(ListA, “A”) go task(ListB, “B”)

  1. // 主协程
  2. for {
  3. ;
  4. }
  5. /**
  6. A队[1]: 小明 使用咖啡机
  7. B队[1]: 威廉 使用咖啡机
  8. B队[2]: 巴克 使用咖啡机
  9. A队[2]: 小红 使用咖啡机
  10. A队[3]: 小王 使用咖啡机
  11. B队[3]: 查理 使用咖啡机
  12. B队[4]: 哈利 使用咖啡机
  13. A队[4]: 宝宝 使用咖啡机
  14. A队[5]: 娜娜 使用咖啡机
  15. B队[5]: 哈瑞 使用咖啡机
  16. B队[6]: 米菲 使用咖啡机
  17. A队[6]: 拉拉 使用咖啡机
  18. A队[7]: 琪琪 使用咖啡机
  19. B队[7]: 珍妮 使用咖啡机
  20. B队[8]: 米奇 使用咖啡机
  21. A队人员已排队完~~~
  22. B队人员已排队完~~~
  23. */

}

  1. <a name="aT5Gc"></a>
  2. ## 协程的并发执行
  3. 同时启动 7 个子协程,由于它们是并发执行的,执行的先后顺序无法保证
  4. ```go
  5. package main
  6. import (
  7. "fmt"
  8. "time"
  9. )
  10. var (
  11. ListA = []string{"小明", "小红", "小王", "宝宝", "娜娜", "拉拉", "琪琪"}
  12. )
  13. func task(i int) {
  14. fmt.Printf("A队[%d]: %s 使用咖啡机 \n", i, ListA[i])
  15. time.Sleep(time.Second)
  16. }
  17. func main() {
  18. for i:=0; i<len(ListA); i++ {
  19. go task(i)
  20. }
  21. for {
  22. ;
  23. }
  24. /*
  25. A队[0]: 小明 使用咖啡机
  26. A队[5]: 拉拉 使用咖啡机
  27. A队[2]: 小王 使用咖啡机
  28. A队[3]: 宝宝 使用咖啡机
  29. A队[4]: 娜娜 使用咖啡机
  30. A队[6]: 琪琪 使用咖啡机
  31. A队[1]: 小红 使用咖啡机
  32. */
  33. }