前言:
此刻姐妹们对“多进程并发的局限性是什么”大体比较关切,小伙伴们都想要剖析一些“多进程并发的局限性是什么”的相关知识。那么小编也在网上收集了一些对于“多进程并发的局限性是什么””的相关知识,希望兄弟们能喜欢,大家快快来学习一下吧!并发意味着程序在运行时有多个执行上下文,对应着多个调用栈。
每一个进程在运行时,都有自己的调用栈和堆,有一个完整的上下文。
从系统的角度讲,多个进程时可以并发的。
并发适用的场景有 4 种:
同时响应图形用户界面和 IO 密集操作服务器面对大量用户请求发挥计算机硬件的能力IO 操作阻塞程序
并发的优势有 3 条:
表现问题模型提高程序的执行效率充分利用固件的异步性
实现并发的主流模型包括 4 种:
多进程,传统并发模型多线程,传统并发模型基于回调的非阻塞/异步 IO,传统并发模型协程
传统并发模型的缺陷包括 2 条:
共享内存的并发,容易在工程中遇到各种奇怪的故障和问题消息传递系统,复制操作在性能上不优越。新的并发方式:协程
Python 中的并发方式叫 协程,用 yield 实现,Go 中把它叫做 goroutine , 也称作协程。Go 中从语言的角度就支持协程。
goroutine 由 Go 的运行时 runtime管理。
使用并发执行一个 Add 函数
func Add(x, y int) { z := x + y fmt.Println(z)}go Add(1, 1)
在函数调用前加上 go 关键字,这次调用就会在一个新的 goroutine 中并发执行。
当被调用的函数返回时,这个 goroutine 也自动结束了。
当这个函数有返回值,在并发执行时,这个返回值会被丢弃。
package mainimport "fmt"func Add(x, y int) { z := x + y fmt.Println(z)}func main() { for i := 0; i<10; i++ { go Add(i,i) }}
想要并行执行 10 次 Add() 函数,可以通过在一个 for 循环中调用 10 次 Add()。但这样会出现协程还未开始执行,主程序就已经退出的情况。
Go 语言的程序机制是,程序从初始化 main package 并执行 main() 函数开始,当 main() 函数返回时,程序退出,且程序不等待其他 goroutine 结束。
解决的办法是使用 Go 的 channel:
package mainimport "fmt"import "sync"import "runtime"var counter int = 0func Count(lock *sync.Mutex) { lock.Lock() counter++ fmt.Println(counter) lock.Unlock()}func main() { lock := &sync.Mutex{} for i:=0; i<10; i++ { go Count(lock) } for { lock.Lock() c := counter lock.Unlock() runtime.Gosched() if c>=10 { break } }}
Go 中获知所有 goroutine 的状态,使用的是并发通信。
区别于共享数据的并发通信模型,Go 采用的是消息的模型。
package main import "fmt"func Count(ch chan int) { fmt.Println("Counting") // 3.执行加减计算 ch <- 1 // 4.通过 ch <- 1 语句向对应的 channel 中写入数据 1,在这个 channel 被读取前,这个操作是阻塞的。}func main() { chs := make([]chan int, 10) // 1.定义一个包含 10 个 channel 的数组 for i := 0; i<10; i++ { // 2.把数组中的每个 channel 分配给 10 个不同的 goroutine chs[i] = make(chan int) go Count(chs[i]) } // 5.在所有的 goroutine 启动完成后 for _, ch := range(chs) { <-ch // 6.从 10 个 channel 中依次读取数据。在对应的 channel 写入数据前,这个操作也是阻塞的。 }}
这样,用 channel 实现了类似锁的功能,进而保证了所有 goroutine 完成后,主函数才返回。
channel 的声明形式:
var chanName chan ElementType
与一般的变量声明不同的地方仅仅是在类型之前加了 chan 关键字。ElementType 指定这个 channel 所能传递的元素类型。
var ch chan int // 声明一个传递类型为 int 的 channelvar m map[string] chan bool // 声明一个 map,元素是 bool 型的 channel
定义一个 channel,直接使用内置的函数 make():
ch := make(chan int) // 声明并初始化一个 int 型的 channel,名为 ch
channel 用法中,最常见的包括写入和读出。
ch <- value // 数据写入至 channel
向 channel 写入数据会导致程序阻塞,直到有其他 goroutine 从这个 channel 中读取数据。
value := <- ch
如果 channel 之前没有写入数据,那么从 channel 中读取数据也会导致程序阻塞,直到 channel 中被写入数据为止。
标签: #多进程并发的局限性是什么