首页 > 其他分享 >golang入门(十一)并发groutine

golang入门(十一)并发groutine

时间:2023-02-21 16:03:35浏览次数:37  
标签:并行 程序执行 golang 并发 线程 当前 time groutine

并发与并行一直两个容易搞混的概念:

  • 并发:同一个时间段,共同运行的任务。任务的在这个时间段内,启动和结束的时间有先后之分的。举例来说:公司的食堂在中午12点-13点之间,可以容纳100人就餐。这100人的就餐任务就是并发的。
  • 并行:同一个时刻,共同启动并运行的任务。任务的结束时间可能有先后之分,但是启动的时刻是一致的。举例来说:田径短跑比赛,10名选手站在起跑线上。一声枪响,所有运动员向终点发起冲刺。这10人的比赛任务就是并行的。

并行需要将多个进程绑定到多个CPU内核上来实现。并行就灵活很多,既可以在多进程多CPU条件下实现,也可以在单核多线程的环境下运行。

备注:进程\线程\协程的概念以及Python的多线程与Golang的groutine之间的区别,资料很多就不详述了,这里主要演示操作。

在Python中,并行通过threading库实现,代码如下:

import threading
import time
import datetime


def Calc(s):
for i in range(1, 6):
s = s + i
print("当前的值是{}".format(s))
time.sleep(1)


def Say(x):
for i in range(1, 6):
print("这是第< {0} > 次说 < {1} >".format(i, x))
time.sleep(1)


# 创建一个列表,用于存储要启动多线程的实例
threads = []
calc = threading.Thread(target=Calc, args=(5,))
# 线程任务追加至队列
threads.append(calc)

say = threading.Thread(target=Say, args=("哈哈",))
threads.append(say)

start = datetime.datetime.now()
for thr in threads:
#把列表中的实例遍历出来后,调用start()方法以线程启动运行
thr.start()

for thr in threads:
"""
让主线程等待线程结束之后最后再结束。
"""
if thr:
thr.join()

timerange = datetime.datetime.now() - start
print('程序执行耗时 {}'.format(timerange))

执行结果,耗时5s左右,说明2个函数是并行的。

% python main.py
当前的值是6
这是第< 1 > 次说 < 哈哈 >
当前的值是8
这是第< 2 > 次说 < 哈哈 >
这是第< 3 > 次说 < 哈哈 >
当前的值是11
这是第< 4 > 次说 < 哈哈 >
当前的值是15
这是第< 5 > 次说 < 哈哈 >
当前的值是20
程序执行耗时 0:00:05.020021


在Go中,并行是通过groutine实现的。

package main

import (
"fmt"
"sync"
"time"
)

// 声明WaitGroup,用于确保主groutine一定晚于子groutine结束
var wg sync.WaitGroup

func Calc(s int) {
// 告知 WaitGroup 执行这个函数的子groutine已结束
defer wg.Done()
for i := 1; i < 6; i++ {
s = s + i
fmt.Println("s当前的值是: ", s)
time.Sleep(time.Second * 1)
}
}

func Say(x string) {
defer wg.Done()
for i := 1; i < 6; i++ {
fmt.Printf("这是第< %d >次说<%s>\n", i, x)
time.Sleep(time.Second * 1)
}
}

func main() {
StartTime := time.Now()
// 告知WaitGroup 会有2个子groutine运行。每完成一个子任务,Add()中的值-1
wg.Add(2)
// 分配启动一个子groutine 运行绑定的函数
go Calc(1)
go Say("哈哈")

// 锁住主groutine的运行,直至声明的Add()中的值减为0
// 类似python中 join()的功能
wg.Wait()

fmt.Println("程序执行结束")

TimeRange := time.Since(StartTime)
fmt.Printf("程序执行耗时 %v", TimeRange)
}

运行结果与python中一致

% go run main.go
这是第< 1 >次说<哈哈>
s当前的值是: 2
s当前的值是: 4
这是第< 2 >次说<哈哈>
s当前的值是: 7
这是第< 3 >次说<哈哈>
s当前的值是: 11
这是第< 4 >次说<哈哈>
s当前的值是: 16
这是第< 5 >次说<哈哈>
程序执行结束
程序执行耗时 5.00587825s


总结:

  • Go在启动并行的语法方面比Python要简单
  • groutine是介于线程与协程之间的东西,比线程更轻量、比协程更自动
  • Python受限于GIL,无论启动多少线程都只能运行在一个CPU内核上。在数据量比较小的情况多并行效率与Go差异不大。
  • 在Go中,线程与groutine是一堆多的关系。多个groutine会被自动分配到多个CPU内核上运行。

标签:并行,程序执行,golang,并发,线程,当前,time,groutine
From: https://blog.51cto.com/830909/6076658

相关文章

  • golang 函数
    go语言中的函数特性go语言中有3种函数:普通函数、匿名函数(没有名称的函数)、方法(定义在struct上的函数)。go语言中不允许函数重载(overload),也就是说不允许函数同名。......
  • Golang错误处理
    Golang中创建错误有两种方式:第一种:errors.New()函数,其返回值类型为*errors.errorString。第二种:fmt.Errorf()函数当使用fmt.Errorf()来创建错误时,核心有以下两......
  • 多线程并发(二):聊聊AQS中的共享锁实现原理
    在上一篇文章多线程并发(一)中我们通过acquire()详细地分析了AQS中的独占锁的获取流程,提到独占锁,自然少不了共享锁,所以我们这边文章就以AQS中的acquireShared()方法为例,......
  • GoLang环境搭建
    goLangIDE选择VsCodeSDK下载首页-Go语言中文网-Golang中文社区(studygolang.com)  选择64位压缩包   下载后解压到磁盘目录 新建目录 C:\gol......
  • Golang基础-闭包
    funcfib()func()int{ varn1,n2int returnfunc()int{ ifn1==0&&n2==0{ n1=1 }else{ n1,n2=n2,n1+n2 } returnn2 }}next......
  • redis的并发竞争问题
    第一种方案:分布式锁1.整体技术方案这种情况,主要是准备一个分布式锁,大家去抢锁,抢到锁就做set操作。2.为什么是分布式锁?因为传统的加锁的做法(如java的synchronized和l......
  • 通过golang编写并发程序监控系统中文件大小并通过prometheus告警
    packagemainimport("fmt""io/ioutil""os""path/filepath""sync")const(maxFileSizeint64=10*1024*1024m......
  • 高并发系统设计之负载均衡
    本文已收录至Github,推荐阅读......
  • golang中的GPM(用户态的线程池)
     全局队列(GlobalQueue):存放等待运行的G。P的本地队列:同全局队列类似,存放的也是等待运行的G,存的数量有限,不超过256个。新建G’时,G’优先加入到P的本地队列,如果......
  • Golang基础-正则表达式
    backticksWhenusingbackticks(`)tomakestrings(Rawstringliterals),backslashes(\)don'thaveanyspecialmeaninganddon'tmarkthebeginningofspecial......