golang多进程并发

前言

以前听说什么golang一把梭什么的很厉害,到现在位置也接触golang半个多月时间了,最主要的时间都是在看document,学习语法。golang什么的变量名大小写区分公有私有神马的太坑爹了。。。最近接触到了golang最为称赞的第一个地方:goroutine。本篇博客先介绍操作系统中的一些基本语法,然后介绍一下goroutine的美妙之处。

【线程, 进程】; 【多进程,多线程】; 【并发,并行】

线程与进程

  1. 概念
    • 线程:是程序执行流的最小单元,是系统独立调度和分配CPU(独立运行)的基本单位。
    • 进程:是资源分配的基本单位。一个进程包括多个线程
  2. 区别
    • 线程与资源分配无关,它属于某一个进程,并与进程内的其他线程一起共享进程的资源。
    • 每个进程都有自己一套独立的资源(数据),供其内的所有线程共享。
    • 不论是大小,开销线程要更“轻量级”
    • 一个进程内的线程通信比进程之间的通信更快速,有效。(因为共享变量)

多进程与多线程

多线程:同一时刻执行多个线程。用浏览器一边下载,一边听歌,一边看视频,一边看网页。。。

多进程:同时执行多个程序。如,同事运行YY,QQ,以及各种浏览器。

并发与并行

并发当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状。.这种方式我们称之为并发(Concurrent)。

并行:当系统有一个以上CPU时,则线程的操作有可能非并发。当一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。

举个例子:

并发就是一个窗口多条队伍,多条队伍轮流使用资源。

并行就是多个窗口,每个窗口一个队伍,队伍之间并行排队。

并发&并行

gotuntine

golang语言中,用go关键词就可以启动并发程序。

我们先看一下下面这个简单的例子,在main函数中依次调用了两次loop函数。

func loop() {
  for i := 0; i < 10; i++ {
    fmt.Printf("%d", i)
  }
}
func main() {
  loop()
  loop()
}

毫无疑问上述代码的运行结果如下:

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9


这个时候我们将main函数代码换成如下

func main() {
  go loop()
  loop()
}

此时loop函数只运行了一次;这是什么原因呢,原来是因为我们的main函数中的第二个loop()执行比较快

go loop()还没有执行的时候,main函数已经运行结束并且退出了。

0 1 2 3 4 5 6 7 8 9

我们可以使用time.Sleep设置延时来等待go loop()执行,这种做法可行,但是显然是不科学的,如果我的go loop()执行很快结束了,而main函数还在等待,这显然是一种资源上的浪费。

那么如何解决的,我们可以用下面的信道来解决这个问题

func main() {
  go loop()
  loop()
  time.Sleep(time.Seoncd) //停顿一秒
}

信道

信道是什么?简单的来说就是goruntine之间相互通讯的东西。类似Linux中的管道,用来在多个进程之间共享资源。

先看一下例子

func main() {
  var chanel chan int = make(chan int)    // 定义信道类型变量 chanel
  go func(msg string) {
    chanel <- msg        // 存消息 chan <- msg
  }("Ping")
  msgStr := <-chanel    // 取消息 msg <- chan
  fmt.Println(msgStr)
}

在上述代码中,我们通过定义chanel变量完成了进程间的消息通讯。

通过存消息和取消息两种方法完成进程间的消息通讯。


通过这种方式我们可以控制进程的结束时间

var quit chan int = make(chan int)
func loop() {
  for i := 0; i < 10; i++ {
    fmt.Printf("%d ", i)
  }
  quit <- 0        // 进程执行结束,存入消息
}
func main() {
  go loop()
  loop()
  <- quit        // 取消息,进程结束
}

我们通过quit来控制loop()的结束时间点,当quit没有取到消息的时候,进程就会阻塞,main函数也就无法继续执行。

如果不用信道来阻塞主线的话,主线就会过早跑完,loop线都没有机会执行、、、

其实,无缓冲的信道永远不会存储数据,只负责数据的流通,为什么这么讲呢?

  • 从无缓冲信道取数据,必须要有数据流进来才可以,否则当前线阻塞
  • 数据流入无缓冲信道, 如果没有其他goroutine来拿走这个数据,那么当前线阻塞

简单来说就是必须有消息流入,并且有消息流出,缺一不可,不然会造成死锁

后续

下一篇博客将会介绍一下死锁以及等待多goruntine的方案


 上一篇
CodeCraft-2019 CodeCraft-2019
华为软件精英挑战赛2019 代码链接(https://github.com/chierqj/CodeCraft-2019) 赛区:西北赛区 队名:赐我一个天命圈 名次:初赛(6),复赛(4),决赛32强 前前后大概经历了好几个版
2019-05-05
下一篇 
HWM-在线分配算法 HWM-在线分配算法
前言最近在公司接触到的项目需要用到HWM算法,网上看了许多资料,简单说HWM是一种基于概率的贪婪式分配算法。算法介绍 算法背景 广告投放 在线分配 最大量分配 Problem example某广告主有三份广告订单,定向分别为 {北京
2019-01-21
  目录