go语言并发编程

Go语言学习笔记—golang并发编程之channel 视频来源于B站Go语言基础进阶视频av56860636 文章为自己整理的学习笔记,侵权即删,谢谢支持! 阅读详情

并 发 编 程

优雅的并发编程范式,完善的并发支持,出色的并发性能是Go语言区别于其他语言的一大特色

并发基础

并发程序的几条优点,让大家认识到并发势在必行:
 并发能更客观地表现问题模型;
 并发可以充分利用CPU核心的优势,提高程序的执行效率;
 并发能充分利用CPU与其他硬件设备固有的异步性。
现在我们已经意识到并发的好处了,那么到底有哪些方式可以实现并发执行呢?就目前而言,并发包含以下几种主流的实现模型。

** 多进程**。多进程是在操作系统层面进行并发的基本模式。同时也是开销最大的模式。在Linux平台上,很多工具链正是采用这种模式在工作。比如某个Web服务器,它会有专门的进程负责网络端口的监听和链接管理,还会有专门的进程负责事务和运算。这种方法的好处在于简单、进程间互不影响,坏处在于系统开销大,因为所有的进程都是由内核管理的。

多线程。多线程在大部分操作系统上都属于系统层面的并发模式,也是我们使用最多的最有效的一种模式。目前,我们所见的几乎所有工具链都会使用这种模式。它比多进程的开销小很多,但是其开销依旧比较大,且在高并发模式下,效率会有响。

基于回调的非阻塞/异步IO。这种架构的诞生实际上来源于多线程模式的危机。在很多高并发服务器开发实践中,使用多线程模式会很快耗尽服务器的内存和CPU资源。而这种模式通过事件驱动的方式使用异步IO,使服务器持续运转,且尽可能地少用线程,降低开销,它目前在Node.js中得到了很好的实践。但是使用这种模式,编程比多线程要复杂,因为它把流程做了分割,对于问题本身的反应不够自然。

协程。协程(Coroutine)本质上是一种用户态线程,不需要操作系统来进行抢占式调度,且在真正的实现中寄存于线程中,因此,系统开销极小,可以有效提高线程的任务并发性,而避免多线程的缺点。使用协程的优点是编程简单,结构清晰;缺点是需要语言的支持,如果不支持,则需要用户在程序中自行实现调度器。目前,原生支持协程的语言还很少。

人的思维模式可以认为是串行的,而且串行的事务具有确定性。线程类并发模式在原先的确定性中引入了不确定性,这种不确定性给程序的行为带来了意外和危害,也让程序变得不可控。
线程之间通信只能采用共享内存的方式。为了保证共享内存的有效性,我们采取了很多措施,比如加锁等,来避免死锁或资源竞争。

我们可以将之前的线程加共享内存的方式归纳为“共享内存系统”,虽然共享内存系统是一种有效的并发模式,但它也暴露了众多使用上的问题。计算机科学家们在近40年的研究中又产生了一种新的系统模型,称为“消息传递系统”。对线程间共享状态的各种操作都被封装在线程之间传递的消息中,这通常要求:发送消息时对状态进行复制,并且在消息传递的边界上交出这个状态的所有权。从逻辑上来看,这个操作与共享内存系统中执行的原子更新操作相同,但从物理上来看则非常不同。由于需要执行复制操作,所以大多数消息传递的实现在性能上并不优越,但线程中的状态管理工作通常会变得更为简单。

协程

执行体是个抽象的概念,在操作系统层面有多个概念与之对应,比如操作系统自己掌管的进程(process)、进程内的线程(thread)以及进程内的协程(coroutine,也叫轻量级线程)。与传统的系统级线程和进程相比,协程的最大优势在于其“轻量级”,可以轻松创建上百万个而不会导致系统资源衰竭,而线程和进程通常最多也不能超过1万个。这也是协程也叫轻量级线程的
原因。

多数语言在语法层面并不直接支持协程,而是通过库的方式支持,但用库的方式支持的功能也并不完整,比如仅仅提供轻量级线程的创建、销毁与切换等能力。如果在这样的轻量级线程中
调用一个同步 IO 操作,比如网络通信、本地文件读写,都会阻塞其他的并发执行轻量级线程,从而无法真正达到轻量级线程本身期望达到的目标。

Go 语言在语言级别支持轻量级线程,叫goroutine。Go 语言标准库提供的所有系统调用操作(当然也包括所有同步 IO 操作),都会出让 CPU 给其他goroutine。这让事情变得非常简单,让轻量级线程的切换管理不依赖于系统的线程和进程,也不依赖于CPU的核心数量。

goroutine

goroutine是Go语言中的轻量级线程实现,由Go运行时(runtime)管理。
假设我们需要实现一个函数Add(),它把两个参数相加,并将结果打印到屏幕上,具体代码如下:

func Add(x, y int) { 
 z := x + y 
 fmt.Println(z) 
} 

那么,如何让这个函数并发执行呢?具体代码如下:
go Add(1, 1)
在一个函数调用前加上go关键字,这次调用就会在一个新的goroutine中并发执行。当被调用的函数返回时,这个goroutine也自动结束了。需要注意的是,如果这个函数有返回值,那么这个
返回值会被丢弃。

package main 
import "fmt" 
func Add(x, y int) { 
 z := x + y 
 fmt.Println(z) 
} 
func main() { 
 for i := 0; i < 10; i++ { 
 go Add(i, i) 
 } 
} 

在上面的代码里,我们在一个for循环中调用了10次Add()函数,它们是并发执行的。可是当你编译执行了上面的代码,就会发现一些奇怪的现象:
“什么?!屏幕上什么都没有,程序没有正常工作!”
是什么原因呢?明明调用了10次Add(),应该有10次屏幕输出才对。要解释这个现象,就涉及Go语言的程序执行机制了。
Go程序从初始化main package并执行main()函数开始,当main()函数返回时,程序退出,且程序并不等待其他goroutine(非主goroutine)结束。
对于上面的例子,主函数启动了10个goroutine,然后返回,这时程序就退出了,而被启动的执行Add(i, i)的goroutine没有来得及执行,所以程序没有任何输出。

并发通信

关键字go的引入使得在Go语言中并发编程变得简单而优雅,但我们同时也应该意识到并发编程的原生复杂性,并时刻对并发中容易出现的问题保持警惕。

并发单元间的通信是最大的问题。
在工程上,有两种最常见的并发通信模型:共享数据和消息。
共享数据是指多个并发单元分别保持对同一个数据的引用,实现对该数据的共享。被共享的数据可能有多种形式,比如内存数据块、磁盘文件、网络数据等。在实际工程应用中最常见的无
疑是内存了,也就是常说的共享内存。
先看看我们在C语言中通常是怎么处理线程间数据共享的

#include <stdio.h> 
#include <stdlib.h> 
#include <pthread.h> 
void *count(); 
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; 
int counter = 0; 
main() 
{ 
 int rc1, rc2; 
 pthread_t thread1, thread2; 
 /* 创建线程,每个线程独立执行函数functionC */ 
 if((rc1 = pthread_create(&thread1, NULL, &add, NULL))) 
 { 
 printf("Thread creation failed: %d\n", rc1); 
 } 
 if((rc2 = pthread_create(&thread2, NULL, &add, NULL))) 
 { 
 printf("Thread creation failed: %d\n", rc2); 
 } 
 /* 等待所有线程执行完毕 */ 
 pthread_join( thread1, NULL); 
 pthread_join( thread2, NULL); 
 exit(0); 
} 
void *count() 
{ 
 pthread_mutex_lock( &mutex1 ); 
 counter++; 
 printf("Counter value: %d\n",counter); 
 pthread_mutex_unlock( &mutex1 ); 
} 

现在我们尝试将这段C语言代码直接翻译为Go语言代码

package main 
import "fmt" 
import "sync" 
import "runtime" 
var counter int = 0 
func Count(lock *sync.Mutex) { 
 lock.Lock() 
 counter++ 
 fmt.Println(z) 
 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 
 } 
 } 
} 

在上面的例子中,我们在10个goroutine中共享了变量counter。每个goroutine执行完成后,将counter的值加1。因为10个goroutine是并发执行的,所以我们还引入了锁,也就是代码中的lock变量。每次对n的操作,都要先将锁锁住,操作完成后,再将锁打开。在主函数中,使用for循环来不断检查counter的值(同样需要加锁)。当其值达到10时,说明所有goroutine都执行完毕了,这时主函数返回,程序退出。事情好像开始变得糟糕了。实现一个如此简单的功能,却写出如此臃肿而且难以理解的代码。

Go语言提供的是另一种通信模型,即以消息机制而非共享内存作为通信方式。
消息机制认为每个并发单元是自包含的、独立的个体,并且都有自己的变量,但在不同并发单元间这些变量不共享。每个并发单元的输入和输出只有一种,那就是消息。这有点类似于进程的概念,每个进程不会被其他进程打扰,它只做好自己的工作就可以了。不同进程间靠消息来通信,它们不会共享内存。

channel

channel是Go语言在语言级别提供的goroutine间的通信方式。我们可以使用channel在两个或多个goroutine之间传递消息。channel是进程内的通信方式,因此通过channel传递对象的过程和调用函数时的参数传递行为比较一致,比如也可以传递指针等。

channel是类型相关的。也就是说,一个channel只能传递一种类型的值,这个类型需要在声明channel时指定。如果对Unix管道有所了解的话,就不难理解channel,可以将其认为是一种类型安全的管道。
在了解channel的语法前,我们先看下用channel的方式重写上面的例子是什么样子的,以此

package main 
import "fmt" 
func Count(ch chan int) { 
 ch <- 1 
 fmt.Println("Counting") 
} 
func main() { 
 chs := make([]chan int, 10) 
 for i := 0; i < 10; i++ { 
 chs[i] = make(chan int) 
 go Count(chs[i]) 
 } 
 for _, ch := range(chs) { 
 <-ch 
 } 
} 

在这个例子中,我们定义了一个包含10个channel的数组(名为chs),并把数组中的每个channel分配给10个不同的goroutine。在每个goroutine的Add()函数完成后,我们通过ch <- 1语句向对应的channel中写入一个数据。在这个channel被读取前,这个操作是阻塞的。在所有的goroutine启动完成后,我们通过<-ch语句从10个channel中依次读取数据。在对应的channel写入数据前,这个操作也是阻塞的。

基本语法

一般channel的声明形式为:var chanName chan ElementType 与一般的变量声明不同的地方仅仅是在类型之前加了chan关键字。ElementType指定这个channel所能传递的元素类型。举个例子,我们声明一个传递类型为int的channel:

var ch chan int 

或者,我们声明一个map,元素是bool型的channel:

var m map[string] chan bool 

定义一个channel也很简单,直接使用内置的函数make()即可:

ch := make(chan int) 

这就声明并初始化了一个int型的名为ch的channel。
在channel的用法中,最常见的包括写入和读出。将一个数据写入(发送)至channel的语法很直观,如下:

ch <- value 

向channel写入数据通常会导致程序阻塞,直到有其他goroutine从这个channel中读取数据。从channel中读取数据的语法是

value := <-ch 

如果channel之前没有写入数据,那么从channel中读取数据也会导致程序阻塞,直到channel中被写入数据为止。我们之后还会提到如何控制channel只接受写或者只允许读取,即单向channel。

select

早在Unix时代,select机制就已经被引入。通过调用select()函数来监控一系列的文件句柄,一旦其中一个文件句柄发生了IO动作,该select()调用就会被返回。Go语言直接在语言级别支持select关键字,用于处理异步IO问题。
select的用法与switch语言非常类似,由select开始一个新的选择块,每个选择条件由case语句来描述。与switch语句可以选择任何可使用相等比较的条件相比,select有比较多的限制,其中最大的一条限制就是每个case语句里必须是一个IO操作,大致的结构如下:

select { 
 case <-chan1: 
 // 如果chan1成功读到数据,则进行该case处理语句
 case chan2 <- 1: 
 // 如果成功向chan2写入数据,则进行该case处理语句
default: 
 // 如果上面都没有成功,则进入default处理流程
} 

可以看出,select不像switch,后面并不带判断条件,而是直接去查看case语句。每个case语句都必须是一个面向channel的操作。比如上面的例子中,第一个case试图从chan1读取
一个数据并直接忽略读到的数据,而第二个case则是试图向chan2中写入一个整型数1,如果这两者都没有成功,则到达default语句。

缓冲机制

之前我们示范创建的都是不带缓冲的channel,这种做法对于传递单个数据的场景可以接受,但对于需要持续传输大量数据的场景就有些不合适了。接下来我们介绍如何给channel带上缓冲,
从而达到消息队列的效果。
要创建一个带缓冲的channel,其实也非常容易:

c := make(chan int, 1024) 

在调用make()时将缓冲区大小作为第二个参数传入即可,比如上面这个例子就创建了一个大小为1024的int类型channel,即使没有读取方,写入方也可以一直往channel里写入,在缓冲区被
填完之前都不会阻塞。

从带缓冲的channel中读取数据可以使用与常规非缓冲channel完全一致的方法,但我们也可以使用range关键来实现更为简便的循环读取:

for i := range c { 
 fmt.Println("Received:", i) 
} 

超时机制

在并发编程的通信过程中,最需要处理的就是超时问题,即向channel写数据时发现channel已满,或者从channel试图读取数据时发现channel为空。如果不正确处理这些情况,很可能会导
致整个goroutine锁死。
使用channel时需要小心,比如对于以下这个用法:

i := <-ch 

不出问题的话一切都正常运行。但如果出现了一个错误情况,即永远都没有人往ch里写数据,那么上述这个读取动作也将永远无法从ch中读取到数据,导致的结果就是整个goroutine永远阻塞并
没有挽回的机会。如果channel只是被同一个开发者使用,那样出问题的可能性还低一些。但如果一旦对外公开,就必须考虑到最差的情况并对程序进行保护。

Go语言没有提供直接的超时处理机制,但我们可以利用select机制。虽然select机制不是专为超时而设计的,却能很方便地解决超时问题。因为select的特点是只要其中一个case已经完成,程序就会继续往下执行,而不会考虑其他case的情况。
基于此特性,我们来为channel实现超时机制:

// 首先,我们实现并执行一个匿名的超时等待函数
timeout := make(chan bool, 1) 
go func() { 
 time.Sleep(1e9) // 等待1秒钟
 timeout <- true
}() 
// 然后我们把timeout这个channel利用起来
select { 
 case <-ch: 
 // 从ch中读取到数据
 case <-timeout: 
 // 一直没有从ch中读取到数据,但从timeout中读取到了数据
}

这样使用select机制可以避免永久等待的问题,因为程序会在timeout中获取到一个数据后继续执行,无论对ch的读取是否还处于等待状态,从而达成1秒超时的效果。这种写法看起来是一个小技巧,但却是在Go语言开发中避免channel通信超时的最有效方法。

channel的传递

传递的数据只是一个整型数,在实际的应用场景中这通常会是一个数据块。
首先限定基本的数据结构:

type PipeData struct { 
 value int
 handler func(int) int
 next chan int
} 

然后我们写一个常规的处理函数。我们只要定义一系列PipeData的数据结构并一起传递给这个函数,就可以达到流式处理数据的目的:

func handle(queue chan *PipeData) { 
 for data := range queue { 
 data.next <- data.handler(data.value) 
 } 
} 

这里我们只给出了大概的样子,限于篇幅不再展开。

单向channel

顾名思义,单向channel只能用于发送或者接收数据。channel本身必然是同时支持读写的,否则根本没法用。假如一个channel真的只能读,那么肯定只会是空的,因为你没机会往里面写数据。同理,如果一个channel只允许写,即使写进去了,也没有丝毫意义,因为没有机会读取里面的数据。所谓的单向channel概念,其实只是对channel的一种使用限制。
我们在将一个channel变量传递到一个函数时,可以通过将其指定为单向channel变量,从而限制该函数中可以对此channel的操作,比如只能往这个channel写,或者只能从这个channel读。
单向channel变量的声明非常简单,如下:
`
var ch1 chan int // ch1是一个正常的channel,不是单向的
var ch2 chan<- float64// ch2是单向channel,只用于写float64数据var ch3 <-chan int // ch3是单向channel,只用于读取int数据

channel的意义:就是在单向channel和双向channel之间进行转换。示例如下:
ch4 := make(chan int)
ch5 := <-chan int(ch4) // ch5就是一个单向的读取channel
ch6 := chan<- int(ch4) // ch6 是一个单向的写入channel
基于ch4,我们通过类型转换初始化了两个单向channel:单向读的ch5和单向写的ch6。

关闭channel

关闭channel非常简单,直接使用Go语言内置的close()函数即可:
close(ch) 在介绍了如何关闭channel之后,我们就多了一个问题:如何判断一个channel是否已经被关闭?我们可以在读取的时候使用多重返回值的方式:
x, ok := <-ch

多核并行化

在执行一些昂贵的计算任务时,我们希望能够尽量利用现代服务器普遍具备的多核特性来尽量将任务并行化,从而达到降低总计算时间的目的。此时我们需要了解CPU核心的数量,并针对性地分解计算任务到多个goroutine中去并行运行。
下面我们来模拟一个完全可以并行的计算任务:计算N个整型数的总和。我们可以将所有整型数分成M份,M即CPU的个数。让每个CPU开始计算分给它的那份计算任务,最后将每个CPU的计算结果再做一次累加,这样就可以得到所有N个整型数的总和:

type Vector []float64
// 分配给每个CPU的计算任务
func (v Vector) DoSome(i, n int, u Vector, c chan int) { 
 for ; i < n; i++ { 
 v[i] += u.Op(v[i]) 
 } 
 c <- 1 // 发信号告诉任务管理者我已经计算完成了
} 
const NCPU = 16 // 假设总共有16核
func (v Vector) DoAll(u Vector) { 
 c := make(chan int, NCPU) // 用于接收每个CPU的任务完成信号
 for i := 0; i < NCPU; i++ { 
 go v.DoSome(i*len(v)/NCPU, (i+1)*len(v)/NCPU, u, c) 
 } 
 // 等待所有CPU的任务完成
 for i := 0; i < NCPU; i++ { 
 <-c // 获取到一个数据,表示一个CPU计算完成了
 } 
 // 到这里表示所有计算已经结束
} 

这两个函数看起来设计非常合理。DoAll()会根据CPU核心的数目对任务进行分割,然后开辟多个goroutine来并行执行这些计算任务。

同步

Go语言的设计者虽然对channel有极高的期望,但也提供了妥善的资源锁方案。

同步锁

Go语言包中的sync包提供了两种锁类型:sync.Mutex和sync.RWMutex。Mutex是最简单的一种锁类型,同时也比较暴力,当一个goroutine获得了Mutex后,其他goroutine就只能乖乖等到这个goroutine释放该Mutex。RWMutex相对友好些,是经典的单写多读模型。在读锁占用的情况下,会阻止写,但不阻止读,也就是多个goroutine可同时获取读锁(调用RLock()方法;而写锁(调用Lock()方法)会阻止任何其他goroutine(无论读和写)进来,整个锁相当于由该goroutine独占。从RWMutex的实现看,RWMutex类型其实组合了Mutex:

type RWMutex struct { 
 w Mutex 
 writerSem uint32
 readerSem uint32
 readerCount int32
 readerWait int32
} 

对于这两种锁类型,任何一个Lock()或RLock()均需要保证对应有Unlock()或RUnlock()调用与之对应,否则可能导致等待该锁的所有goroutine处于饥饿状态,甚至可能导致死锁。锁的典型使用模式如下:

var l sync.Mutex 
func foo() { 
 l.Lock() 
 defer l.Unlock() 
 //... 
} 

全局唯一性操作

对于从全局的角度只需要运行一次的代码,比如全局初始化操作,Go语言提供了一个Once类型来保证全局的唯一性操作,具体代码如下:

var a string
var once sync.Once 
func setup() { 
 a = "hello, world" 
} 
func doprint() { 
 once.Do(setup) 
 print(a) 
} 
func twoprint() { 
 go doprint() 
 go doprint() 
} 
【高级】系统架构师 | 2026年上半年案例分析真题 标准答案:系统因缺乏足够历史数据(用户行为、物品信息或评分等),难以做出准确推荐的问题。另外两种:物品冷启动(新课程 / 新知识点缺少互动数据)系统冷启动(平台上线初期整体数据稀缺)类型典型表现常见缓解用户冷启动新注册学员无历史问卷/前测、热门兜底、人口统计学特征、知识图谱前置测评物品冷启动新课无人学无人评内容特征推荐、专家标注、探索流量系统冷启动新平台双边都稀缺规则引擎、运营冷启、知识图谱强约束路径本题已点明「用户冷启动」,另外两种按推荐系统经典三分法作答即可。 阅读详情

相关推荐

OpenVins解析:基于滤波框架的SLAM

这一方式存在的关键问题是匹配耗时很长,对性能影响显著。可以参考ORBSLAM3中的匹配方式来对其优化,比如左右目匹配可以在极线上搜索,前后帧可以利用运动先验投影匹配。理论上加入路标点会提升精度,代价是增加了计算量。着重说下基于描述子的匹配:OpenVins中匹配的方式是robust_match(),里面是调用的opencv的。openvins中不仅仅进行了传统的MSCKF更新(状态向量中不包含路标点),还在。中进行了包含路标点的估计更新。图像帧到来时,利用IMU递推得到的位姿给该图像帧赋初值。

qq_18076309的博客 4081

【golang学习之旅】Go 语言并发编程(goroutine、channel 的使用)

✅ 适合人群:Golang 开发者 | 并发编程初学者 | 后端开发工程师✅ 文章亮点:深入解析 Goroutine & Channel + 代码示例 + 实战场景✅ 目标:掌握 Go 并发编程核心,让你的代码更高效、更强大!Goroutine是Go语言的轻量级线程,由Go运行时管理,而非操作系统。相比传统线程,Goroutine占用内存小:默认仅2KB栈空间,可动态扩展调度高效:Go运行时管理Goroutine的调度,无需手动创建线程启动成本低:创建Goroutine比创建线程的开销小很多。

程序员林北北的博客 1257

STM32F4串口接收ATGM336H GPS数据,手把手教你解析NMEA协议并转换经纬度格式

本文详细介绍了如何使用STM32F4开发板通过串口接收ATGM336H GPS模块的NMEA协议数据,并解析GNRMC语句获取经纬度信息。内容涵盖硬件连接、NMEA协议深度解析、数据校验实现以及经纬度格式转换的数学原理与代码实现,为嵌入式开发者提供完整的GPS数据处理解决方案。

weixin_42522575的博客 499

Go 语言(Golang)并发编程通俗易懂案例

Go 语言(Golang)天生支持并发编程,它的并发模型基于轻量级的 goroutine 和通信顺序进程(CSP)的思想。Goroutine 是 Go 语言中的并发执行单元,通过通道(channel)来实现不同 goroutine 之间的通信。

weixin_43425950的博客 886

金融风控实战:用Python从零搭建贷款违约预测模型(附完整数据集)

本文详细介绍了如何使用Python从零构建金融风控中的贷款违约预测模型,涵盖数据清洗、特征工程、模型构建与评估等全流程。通过实战案例展示逻辑回归、XGBoost和LightGBM三大算法的对比,特别强调AUC-ROC指标在金融风控中的重要性,并附完整数据集和代码实现。

weixin_29175469的博客 241

ESP32小车DIY:从零搭建无线遥控智能车(附完整代码与避坑指南)

本文详细介绍了如何从零开始DIY一台基于ESP32的无线遥控智能小车。内容涵盖核心硬件选型、电路设计、低延迟ESP-NOW无线通信协议的配置与实战,以及双电机差速控制算法与PWM调速的实现。文章提供了完整的代码示例和关键的避坑指南,旨在帮助开发者快速构建稳定可靠的智能车平台,并为进一步的功能扩展奠定基础。

gamma的博客 471

Go语言的并发编程

1.1 什么是并发编程并发编程是指在同一时间段内执行多个任务。与并行编程不同,并行编程强调在物理上同时执行多个任务,而并发编程则着眼于任务的逻辑关联。并发编程使得程序在处理 I/O 绑定等情况下更加高效。1.2 为什么选择Go语言进行并发编程Go语言的设计初衷之一就是为了简化并发编程。它通过内置的goroutine和channel,使得并发编程变得直观易懂。相比于其他语言的线程模型,Go的并发模型更为轻量和高效。Go语言的并发编程为开发者提供了一种简单而强大的工具,使得处理并发任务变得更加高效。

2501_90443644的博客 1112

无迹粒子滤波(Unscented Particle Filter)的定义与讲解

无迹粒子滤波通过结合无迹变换与粒子滤波的优势,能够有效处理非线性和非高斯状态估计问题。通过上述公式,我们可以更清晰地理解无迹粒子滤波的工作原理及其数学基础。

985工科博士毕业,专攻定位、导航和滤波等算法研究。从业10年,主要使用MATLAB 571

14 go语言(golang) - 并发编程goroutine和channel

并发编程是指在计算机程序中同时执行多个计算任务的技术。这种编程方式旨在利用多核处理器的计算能力,提高程序的执行效率和响应速度。而Go 语言的并发编程主要依赖于两个核心概念:Goroutine 和 Channel。

瑞瑞的博客 1082

【UVM实战】第七章:UVM中的寄存器模型(1)寄存器模型简介

寄存器模型简介~

悟已往之不谏 知来者之可追 2072

大数据领域数据架构:租赁行业数据架构的创新思路

租赁行业作为“资产连接需求”的核心业态,其业务本质围绕**“资产全生命周期”与“风险管控”展开,但传统数据架构因“数据孤岛、实时性缺失、多模态处理能力弱”等痛点,无法支撑精细化运营需求。本文结合大数据技术演进与租赁业务特性,提出“湖仓一体+实时计算+智能分析”**的创新数据架构:通过多源数据融合打破信息壁垒,用实时流处理实现设备故障预警与风险动态感知,以资产主题建模整合全生命周期数据,最终通过机器学习模型实现智能风险预测与决策支持。

软件工程实践的博客 393

golang笔记10--go语言并发编程模块 goroutine

golang笔记10--go语言的并发编程模块 goroutine1 介绍2 Goroutine2.1 goroutine2.2 go语言的调度器3 注意事项4 说明 1 介绍 本文继上文 golang笔记09–go语言测试与性能调优, 进一步了解 go语言的并发编程模块 --goroutine,以及相应注意事项。 具体包括 : goroutine 和 go语言的调度器 等内容。 2 Goroutine 2.1 goroutine 主流的并发模型包括:多进程、多线程、基于回调的非阻塞|异步IO、协程 等方式

脚步不能达到的地方,眼光可以达到;眼光不能达到的地方,精神可以飞到 480

Unity内存优化:从崩溃到流畅的终极指南

Emscripten 为 WebAssembly 设定的内存布局(Static、Stack 和 Heap)为开发者提供了一个清晰的内存管理框架。理解这些内存区域的特性和用途,有助于开发者在 WebGL 项目中更有效地管理内存,优化性能,减少内存使用峰值。在 Unity WebGL 中,Dynamic Memory 是 UnityHeap 的主要组成部分,负责存储游戏运行时所需的各种数据。Dynamic Memory 主要分为两类:Managed Memory 和 Native Memory。

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 358

Go语言并发编程

Go语言并发编程 chan实现携程之间的同步通信 //示例说明如下 //1. 创建了10个通道,并发起10个协程 //2. 通道没有设置缓存大小,所以消息发送是会阻塞的,直到接收方准备好 func Count(ch chan int, id int) { fmt.Printf("count function %v", id) fmt.Println() ch <- 1 } func main() { var chs [10]chan int //chs := mak

永远sayYES的博客 184

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

【go语言】并发编程

是一个用于描述程序中操作之间因果顺序的规则。在并发编程中,happen-before 机制定义了如何确保一个操作在另一个操作之前发生,并且保证一个操作的结果能够对其他操作可见。具体而言,程序顺序规则(Program Order Rule):在同一个 goroutine 内,代码的执行顺序是保证的,即一个操作发生在前一个操作之后。同步规则(Synchronization Rule):一个 goroutine 对 channel 的发送操作(ch <- x。

加油,考上985的研究生 1476

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

golang笔记11--go语言并发编程模块 channel

golang笔记11--go语言并发编程模块 channel1 介绍2 Channel2.1 channel2.2 使用Channel等待任务结束2.3 使用Channel进行树的遍历2.4 用select进行调度2.5 传统同步机制3 注意事项4 说明 1 介绍 本文继上文 golang笔记10–go语言并发编程模块 goroutine, 进一步了解 go语言的并发编程模块 --channel,以及相应注意事项。 具体包括 : channel、使用Channel等待任务结束、使用Channel进行树的遍历

脚步不能达到的地方,眼光可以达到;眼光不能达到的地方,精神可以飞到 544

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

16 go语言(golang) - 并发编程select和workerpool

首先,定义一个WorkerPool最大工作者数(maxWorkers:控制同时运行的 goroutine 的最大数量。任务队列(taskQueue:用于存储待处理任务,通常使用channel来实现。停止信号(stopSignal:一个通道,用于发送停止信号给所有工作者,让它们停止执行。同步机制:如互斥锁(sync.Mutex)或 WaitGroup(),用于同步和等待所有工作者完成。// 池stopSignal chan int // 停止信号,接受到数据时时停止// 保证停止后不能再提交任务。

瑞瑞的博客 1291

go语言的并发编程

并发编程是 Go语言的一个重要特性,而 go语言也是基于此而设计出来的。在之前的文章中,我们已经对 runtime方法进行了详细介绍,这次文章将对 runtime方法进行深入分析,并讲解如何在go-gc中使用该方法。在上述代码中,我们将变量 runtime写入内存中,但是我们并没有将线程添加到内存中,因为我们在前面的介绍中已经知道,只要有一个线程进入内存,那么其他线程也就无法获得任何数据。当存在多个线程时,这些线程在一个线程中执行,如果有一个线程需要返回,则将在这个执行的线程之外的其他线程中进行;

alike_u的博客 883
上一篇: jvm中的垃圾回收器
下一篇: GO语言中的方法
过去日记
过去日记 新星创作者: 后端开发技术领域 新星创作者: 后端开发技术领域
博客等级 码龄3年 5343粉丝 225原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

过去日记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值