go语言中实现生产者-消费者模式有哪些方法呢

1. 简介

本文将介绍在 Go 语言中实现生产者消费者模式的多种方法,并重点探讨了通道、条件变量的适用场景和优缺点。我们将深入讨论这些方法的特点,以帮助开发者根据应用程序需求选择最适合的方式。通过灵活运用 Go 语言提供的并发原语,我们能够实现高效、可靠的生产者消费者模式,提升系统的并发性能和可维护性。

2. 生产者-消费者模式介绍

2.1 生产者-消费者模式能够带来的好处

生产者消费者模式是一种常见的并发编程模式,用于解决生产者和消费者之间的数据传递和处理问题。在该模式中,生产者负责生成数据(生产),而消费者负责处理数据(消费)。生产者和消费者在时间上是解耦的,它们可以独立地以不同的速度执行。生产者消费者模式在并发编程中具有重要性,有以下几个方面的作用:

  1. 解耦生产者和消费者: 生产者和消费者之间通过中间的数据缓冲区(如通道)进行通信,从而实现了解耦。生产者和消费者可以独立地进行工作,无需关心对方的状态或执行速度。
  2. 平衡资源利用和处理能力: 生产者消费者模式可以平衡生产者和消费者之间的资源利用和处理能力。生产者可以根据消费者的处理能力进行生产,并且消费者可以根据生产者的速度进行消费,从而避免资源的浪费或瓶颈。
  3. 提高系统的并发性和响应性: 生产者消费者模式允许并发执行生产者和消费者的任务,从而提高系统的并发性和响应性。通过并发处理数据,可以更好地利用多核处理器和异步执行,从而加快系统的处理速度。
  4. 实现异步通信和处理: 生产者消费者模式使得生产者和消费者可以异步地进行数据通信和处理。生产者可以在需要时生成数据,并将其放入缓冲区中,而消费者可以在需要时从缓冲区中获取数据进行处理,从而实现异步的数据交换和处理。
  5. 提供可扩展性和模块化: 生产者消费者模式提供了一种可扩展和模块化的设计方式。通过将生产者和消费者解耦,可以方便地添加更多的生产者或消费者,以适应系统需求的变化,同时保持代码的可读性和维护性。

总之,生产者消费者模式在并发编程中起着重要的作用,通过解耦、平衡资源利用、提高并发性和响应性等方面的优势,可以帮助构建高效、可扩展的并发系统。

2.2 具体场景举例

生产者消费者模式在实际的软件开发中有广泛的应用。以下是几个常见的实际例子:

  1. 日志处理: 在日志处理中,可以将日志的生成视为生产者,而日志的消费(如写入文件、发送到远程服务器等)视为消费者。通过使用一个日志通道,生产者可以将日志消息发送到通道,而消费者则从通道中接收日志消息并进行相应的处理。这样可以有效地解耦日志的生成和消费,避免日志处理对业务逻辑的影响。
  2. 任务队列: 在某些任务调度和处理场景中,可以使用生产者消费者模式来实现任务队列。生产者负责将任务添加到队列中,而消费者则从队列中获取任务并进行处理。这种方式可以实现任务的异步处理和负载均衡,提高系统的并发性能。
  3. 缓存更新: 在某些缓存系统中,生产者消费者模式可用于实现缓存更新的异步处理。当数据发生变化时,生产者负责生成更新请求,而消费者则负责将更新应用到缓存中。通过将更新请求发送到缓存通道,可以实现异步的缓存更新,提高系统的响应性能和吞吐量。

在上述例子中,生产者和消费者在同一个单机环境中协同工作,通过使用通道或队列等机制进行数据交换和任务处理。这种设计可以提高系统的并发性能、解耦数据生成和消费的逻辑,以及实现异步处理等好处。

3. 实现方式

3.1 channel的实现

使用通道是生产者消费者模式的另一种常见实现方式,它可以提高并发性能和降低通信开销。下面是使用带缓冲的通道实现生产者消费者模式的示例代码:

package main

import (
        "fmt"
        "time"
)

func producer(ch chan<- int) {
        for i := 1; i <= 5; i++ {
                ch <- i // 将数据发送到通道
                fmt.Println("生产者生产:", i)
                time.Sleep(time.Second) // 模拟生产过程
        }
        close(ch) // 关闭通道
}

func consumer(ch <-chan int, done chan<- bool) {
        for num := range ch {
                fmt.Println("消费者消费:", num)
                time.Sleep(2 * time.Second) // 模拟消费过程
        }
        done <- true // 通知主线程消费者已完成
}

func main() {
        ch := make(chan int, 3)  // 创建带缓冲的通道
        done := make(chan bool) // 用于通知主线程消费者已完成

        go producer(ch) // 启动生产者goroutine
        go consumer(ch, done) // 启动消费者goroutine

        // 主线程等待消费者完成
        <-done
        fmt.Println("消费者已完成")

        // 主线程结束,程序退出
}

在示例代码中,producer函数是生产者函数,它通过通道将数据发送到消费者。consumer函数是消费者函数,它从通道中接收数据并进行消费。main函数是程序的入口,它创建了一个整型通道和一个用于通知消费者完成的通道。

通过go关键字,我们在main函数中启动了生产者和消费者的goroutine。生产者不断地向通道发送数据,而消费者通过range语句从通道中循环接收数据,并进行相应的处理。当通道被关闭后,消费者goroutine会退出循环,并向done通道发送一个通知,表示消费者已完成。

最后,主线程通过<-done语句等待消费者完成,一旦收到通知,输出相应的消息,程序执行完毕。

这个示例展示了使用Go语言的channel和goroutine实现生产者消费者模式的基本流程。通过channel进行数据传递和同步,以及使用goroutine实现并发执行,可以轻松地实现生产者消费者模式的功能。

3.2 互斥锁和条件变量的实现

在Go语言中,可以使用互斥锁(Mutex)和条件变量(Cond)来实现生产者消费者模式。互斥锁用于保护共享资源的访问,而条件变量用于在特定条件下进行线程间的通信和同步。下面是使用互斥锁和条件变量实现生产者消费者模式的示例代码:

package main

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

type Data struct {
        Value int
}

type Queue struct {
        mutex      sync.Mutex
        cond       *sync.Cond
        buffer     []Data
        terminated bool
}

func NewQueue() *Queue {
        q := &Queue{}
        q.cond = sync.NewCond(&q.mutex)
        return q
}

func (q *Queue) Produce(data Data) {
        q.mutex.Lock()
        defer q.mutex.Unlock()

        q.buffer = append(q.buffer, data)
        fmt.Printf("Produced: %d\n", data.Value)

        // 唤醒等待的消费者
        q.cond.Signal()
}

func (q *Queue) Consume() Data {
        q.mutex.Lock()
        defer q.mutex.Unlock()

        // 等待数据可用
        for len(q.buffer) == 0 && !q.terminated {
                q.cond.Wait()
        }

        if len(q.buffer) > 0 {
                data := q.buffer[0]
                q.buffer = q.buffer[1:]
                fmt.Printf("Consumed: %d\n", data.Value)
                return data
        }

        return Data{}
}

func (q *Queue) Terminate() {
        q.mutex.Lock()
        defer q.mutex.Unlock()

        q.terminated = true

        // 唤醒所有等待的消费者
        q.cond.Broadcast()
}

func main() {
        queue := NewQueue()

        // 启动生产者
        for i := 1; i <= 3; i++ {
                go func(id int) {
                        for j := 1; j <= 5; j++ {
                                data := Data{Value: id*10 + j}
                                queue.Produce(data)
                                time.Sleep(time.Millisecond * 500) // 模拟生产时间
                        }
                }(i)
        }

        // 启动消费者
        for i := 1; i <= 2; i++ {
                go func(id int) {
                        for {
                                data := queue.Consume()
                                if data.Value == 0 {
                                        break
                                }
                                // 处理消费的数据
                                time.Sleep(time.Millisecond * 1000) // 模拟处理时间
                        }
                }(i)
        }

        // 等待一定时间后终止消费者
        time.Sleep(time.Second * 6)
        queue.Terminate()

        // 等待生产者和消费者完成
        time.Sleep(time.Second * 1)
}

在上述示例中,我们创建了一个 Queue 结构体,其中包含了一个互斥锁和一个条件变量。生产者通过 Produce 方法向队列中添加数据,并使用条件变量的 Signal 方法唤醒等待的消费者。消费者通过 Consume 方法从队列中取出数据,如果队列为空且未终止,则通过条件变量的 Wait 方法来阻塞自己。当有数据被生产或终止信号发出时,生产者唤醒等待的消费者。

在主函数中,我们启动了多个生产者和消费者的 goroutine,它们并发地进行生产和消费操作。通过适当的延时模拟生产和消费的时间,展示了生产者和消费者之间的协调工作。

最后,我们通过调用 queue.Terminate() 方法来终止消费者的执行,并通过适当的延时等待生产者和消费者完成。

通过使用互斥锁和条件变量,我们可以实现生产者消费者模式的线程安全同步,确保生产者和消费者之间的正确交互。这种实现方式具有较低的复杂性,并提供了对共享资源的有效管理和控制。

4. 实现方式的比较

4.1 channel的实现方式

channel提供了内置的同步和通信机制,隐藏了底层的同步细节,使得代码更简洁和易于使用。通道的发送和接收操作是阻塞的,可以自动处理线程的等待和唤醒,避免了死锁和竞态条件的风险。此外,通道在语言层面提供了优化的机制,能够高效地进行线程间通信和同步。

使用channel实现生产者消费者模式适用于大多数常见的并发场景,特别是需要简单的同步和协调、容易理解和维护以及并发安全性的情况下。

4.2 互斥锁和条件变量的实现方式

使用互斥锁和条件变量实现生产者消费者模式更灵活和精细。互斥锁和条件变量可以提供更细粒度的控制,例如在特定条件下等待和唤醒线程,以及精确地管理共享资源的访问。这种灵活性和精细度使得互斥锁和条件变量适用于需要更复杂的线程间同步和通信需求的场景。

下面举一个适合使用sync.Cond实现生产者消费者模式的场景来说明一下。假设有一个任务队列,任务具有不同的优先级,高优先级任务应该优先被消费者线程处理。在这种情况下,可以使用sync.Cond结合其他数据结构来实现优先级控制。代码实现如下:

import (
        "sync"
)

type Task struct {
        Priority int
        // 其他任务相关的字段...
}

type TaskQueue struct {
        cond      *sync.Cond
        tasks     []Task
}

func (q *TaskQueue) Enqueue(task Task) {
        q.cond.L.Lock()
        q.tasks = append(q.tasks, task)
        q.cond.Signal() // 通知等待的消费者
        q.cond.L.Unlock()
}

func (q *TaskQueue) Dequeue() Task {
        q.cond.L.Lock()
        for len(q.tasks) == 0 {
                q.cond.Wait() // 等待条件满足
        }
        task := q.findHighestPriorityTask()
        q.tasks = removeTask(q.tasks, task)
        q.cond.L.Unlock()
        return task
}

func (q *TaskQueue) findHighestPriorityTask() Task {
        // 实现根据优先级查找最高优先级任务的逻辑
        // ...
}

func removeTask(tasks []Task, task Task) []Task {
        // 实现移除指定任务的逻辑
        // ...
}

在上述代码中,TaskQueue结构体包含一个条件变量cond和一个任务切片tasks,每个任务具有优先级属性。Enqueue方法用于向队列中添加任务,并通过cond.Signal()通知等待的消费者线程。Dequeue方法通过cond.Wait()等待条件满足,然后从队列中选择最高优先级的任务进行处理。

这个例子展示了一个场景,即消费者线程需要根据任务的优先级来选择任务进行处理。使用sync.Cond结合其他数据结构可以更好地实现复杂的优先级控制逻辑,以满足特定需求。相比之下,使用channel实现则较为复杂,需要额外的排序和选择逻辑。

4.3 总结

选择合适的实现方法需要综合考虑场景需求、代码复杂性和维护成本等因素。通道是 Go 语言中推荐的并发原语,适用于大多数常见的生产者消费者模式。如果需求较为复杂,需要更细粒度的控制和灵活性,可以考虑使用互斥锁和条件变量。

5. 总结

生产者消费者模式在并发编程中扮演着重要的角色,通过有效的线程间通信和协作,可以提高系统的并发性能和可维护性。本文中,我们通过比较不同的方法,探讨了在 Go 语言中实现生产者消费者模式的多种选择。

首先,我们介绍了通道作为实现生产者消费者模式的首选方法。通道提供了简单易用的并发原语,适用于大多数常见的生产者消费者场景。

其次,我们提及了互斥锁和条件变量作为更灵活的控制和同步机制。它们适用于复杂的生产者消费者模式需求,允许自定义操作顺序、条件等待和唤醒。然而,使用互斥锁和条件变量需要注意避免死锁和性能瓶颈的问题。

在实际应用中,我们需要根据具体的需求和性能要求来选择合适的方法。通道是最常用和推荐的选择,提供了简单和可靠的线程间通信方式。互斥锁和条件变量适用于复杂的场景,提供了更灵活的控制和同步机制,但需要权衡其复杂性。

综上所述,通过选择合适的方法来实现生产者消费者模式,我们能够充分发挥 Go 语言的灵活性和便利性,提高系统的并发性能和可维护性。在实际应用中,根据需求选择通道或互斥锁和条件变量,能够实现高效的生产者消费者模式,从而提升应用程序的并发能力。

本文转载于网络 如有侵权请联系删除

相关文章

  • SPPNet的原理[通俗易懂]

    大家好,又见面了,我是你们的朋友全栈君。简介SPPNet的英文名称是SpatialPyramidPoolingConvolutionalNetworks,翻译成中文是“空间金字塔池化卷积网络”。paper地址https://arxiv.org/pdf/1406.4729.pdf原理SPPNet主要做了一件事:将CNN的输入从固定尺寸改进为任意尺寸。例如,在普通的CNN结构中,输入的尺寸往往是固定的(如224*224*3),输出可以看做是一个固定维数的向量。SPPNet在普通的CNN结构中加入了ROI池化层(ROIPooling),使得网络的输入图像可以是任意尺寸的,输出则不变,同样是一个固定维数的向量。ROI池化层一般跟在卷积层后面,它的输入是任意大小的卷积,输出是固定维数的向量,如图所示: 为什么ROI池化层能够把任意大小的卷积特征转换成固定长度的向量不妨设卷积层的输出的宽度为w,高度为h,通道为c。不管输入的图像尺寸是多少,卷积层的通道数都不会变,也就是说c是一个常数。而w,h会随着输入图像尺寸的变化而变化,可以看做是两个变量。以上图中的ROI池化层为例,它首先把卷积层划分为4*4

  • 如何给MySQL共享表空间扩容

    一.什么是共享表空间和独占表空间共享表空间以及独占表空间都是针对数据的存储方式而言的。共享表空间: 某一个数据库的所有的表数据,索引文件全部放在一个文件中,默认这个共享表空间的文件路径在data目录下。默认的文件名为:ibdata1 初始化为10M。独占表空间: 每一个表都将会生成以独立的文件方式来进行存储,每一个表都有一个.frm表描述文件,还有一个.ibd文件。其中这个文件包括了单独一个表的数据内容以及索引内容,默认情况下它的存储位置也是在表的位置之中。两者之间的优缺点共享表空间:优点:可以将表空间分成多个文件存放到各个磁盘上。数据和文件放在一起方便管理。缺点:所有的数据和索引存放到一个文件中以为着将有一个很常大的文件,虽然可以把一个大文件分成多个小文件,但是多个表及索引在表空间中混合存储,这样对于一个表做了大量删除操作后表空间中将会有大量的空隙,特别是对于统计分析,日值系统这类应用最不适合用共享表空间。独立表空间:在配置文件(my.cnf)中设置:innodb_file_per_table优点:1.每个表都有自已独立的表空间。2.每个表的数据和索引都会存在自己的表空间中。3.可以

  • 使用kmp算法匹配字符串来查找文件(java版本)-2

    前言接上篇文章,这里完成改文章的后部分,以python编写的版本正文如下同时,我也对原先写的python代码进行了修改,使用KMP算法python实现KMP算法代码其python实现的KMP算法核心代码如下defkmpSearchStrByStr(totalStr,strSearch,kmpTable): #kmp算法查找 #返回字符串中包含搜索串的个数 listSearch=list(strSearch) listTotal=list(totalStr) s=0 t=0 existCount=0 while((s<len(listSearch))&(t<len(listTotal))): if(listSearch[s]==listTotal[t]): if((s+1)!=len(listSearch)): s+=1 t+=1 else: existCount+=1 if((len(listTotal)-(t+1))>=len(listSearch)): s=0 t+=1 else: break; elif(s==0): s=0 t+=1 else:

  • 携程集团机票业务技术总监宋涛:扛得住流量洪峰,才是优秀架构师

     腾讯云开发者社区沙龙online「高可用结构之流量洪峰」专题分享倒计时1天! 本文是腾讯云开发者社区对此次活动出品人,携程集团机票业务技术总监宋涛老师的特别约稿,来跟大家谈一谈:架构师究竟是什么? 一、“架构师”究竟是什么?在软件行业,是否要设立专职架构师,是一个充满争议的话题。一方面,技术日新月异,架构的重要性日益增长,这种情况下需要有人带领大家做重大的架构规划并落地实施;另一方面,架构师又常常会因为架构上的各种坑而被大家抱怨,甚至有一部分公司取消了专职架构师的职位。在我看来,架构师更像是一种职责,一种各级技术人员或多或少都会涉及到的职责。其中既包括总裁级别的杰出工程师(DistinguishedEngineer)设定技术方向、规划和规范,也包括一线工程师进行框架选择、技术迭代。需不需要设立专职架构师是一个见仁见智的问题。现在很多的国内外互联网大厂中,其实是没有架构师这个职位的。但这并不妨碍技术人在架构领域不断做出新的突破。二、成为一名优秀的架构师需要有哪些特质?在我看来,要成为一名优秀的架构师需要有三方面的特质:首先,架构师要对业务领域非常了解,并有足够的能力来抽象出架构和系统相

  • WebGL简易教程(十二):包围球与投影

    目录1.概述2.实现详解3.具体代码4.参考1.概述在之前的教程中,都是通过物体的包围盒来设置模型视图投影矩阵(MVP矩阵),来确定物体合适的位置的。但是在很多情况下,使用包围盒并不方便计算,可以利用包围盒再生成一个包围球,利用包围球来设置MVP矩阵。在《WebGL简易教程(十):光照》中,给地形赋予了固定方向的平行光。这篇教程的例子就是想模拟在平行光的视角下地形的情况。对于点光源光,可以用透视投影来实现渲染的效果;而平行光就需要通过正射投影来模拟。并且,这种正射并不是垂直到达地面,而是附带一定角度[1]: 在这种情况下使用包围盒来计算合适的位置有点难度,使用包围球来设置MVP矩阵更加方便。2.实现详解包围球是利用包围盒生成的,所以首先需要定义一个球体对象://定义一个球体 functionSphere(cuboid){ this.centerX=cuboid.CenterX(); this.centerY=cuboid.CenterY(); this.centerZ=cuboid.CenterZ(); this.radius=Math.max(Math.max(cuboid.Leng

  • 代码覆盖率--gcov/lcov/gcovr

    统计C/C++代码覆盖率的工具很多,比如OpenCppCoverage可以与VS工具配合,获取并展示代码覆盖率简单直观,但是在Linux、Mac等系统该如何统计呢?一般的持续集成工具(Jenkins、gitlab-ci等)中又该如何统计呢?准备工具请参考教程安装即可:GCCCMakeGoogleTestgcovlcovgcovr代码覆盖率代码覆盖率一般包含以下几种类型:函数覆盖率:描述有多少比例的函数经过了测试。语句覆盖率:描述有多少比例的语句经过了测试。分支覆盖率:描述有多少比例的分支(例如:if-else,case语句)经过了测试。条件覆盖率:描述有多少比例的可能性经过了测试。因此一般的覆盖率结果也分为几种不同的类型。gcovgcov是由gcc工具链提供的代码覆盖率生成工具,可以很方便的和GCC编译器配合使用,通常情况下,直接安装gcc工具链,也就同时包含了gcov命令行工具。对于代码覆盖率工具所做的工作,可以简单的理解为:标记一次运行过程中,哪些代码被执行过,哪些没有执行。 因此,即便没有测试代码,直接运行编译产物也可以得到代码的覆盖率。只不过,通常情况下这样得到的覆盖率较低罢了

  • LinkedHashMap 源码详细分析(JDK1.8)

    1.概述LinkedHashMap继承自HashMap,在HashMap基础上,通过维护一条双向链表,解决了HashMap不能随时保持遍历顺序和插入顺序一致的问题。除此之外,LinkedHashMap对访问顺序也提供了相关支持。在一些场景下,该特性很有用,比如缓存。在实现上,LinkedHashMap很多方法直接继承自HashMap,仅为维护双向链表覆写了部分方法。所以,要看懂LinkedHashMap的源码,需要先看懂HashMap的源码。关于HashMap的源码分析,本文并不打算展开讲了。大家可以参考我之前的一篇文章“HashMap源码详细分析(JDK1.8)”。在那篇文章中,我配了十多张图帮助大家学习HashMap源码。本篇文章的结构与我之前两篇关于Java集合类(集合框架)的源码分析文章不同,本文将不再分析集合类的基本操作(查找、遍历、插入、删除),而是把重点放在双向链表的维护上。包括链表的建立过程,删除节点的过程,以及访问顺序维护的过程等。好了,接下里开始分析吧。2.原理上一章说了LinkedHashMap继承自HashMap,所以它的底层仍然是基于拉链式散列结构。该结构由数

  • 腾讯云DDoS高防包BGP高防包异地防护方案

    需求背景受客观因素影响,DDoS高防包仅支持腾讯云北京,上海,广州区域的用户,并承诺全力防护能力。全力防护指以成功防护每一次DDoS攻击为目标,整合当前本地清洗中心能力,同时会根据当时的实际网络状态进行动态调整,全力对攻击进行抵御。除此之外,中国大陆成都、重庆等区域尚未上线高防包产品。如果用户业务源站部署在腾讯云,并且需要使用腾讯云非源站所在地区的DDoS高防包防护能力时,可参考本方案。 防护方案本方案主要由DDoS高防包、CLB负载均衡、源站业务Server组成。在具有DDoS高防包资源的地区部署CLB负载均衡,并将其与DDoS高防包进行绑定。配置CLB的内网回源规则,确保通过CLB的公网IP可以访问业务。 常态化情况下,业务可根据需要解析到源站业务的公网IP(或直接解析到异地的CLB公网IP),业务流量就近访问源站。 在发生攻击后,将业务解析到CLB的IP,对DDoS攻击流量进行清洗,完成清洗后,由CLB通过内网专线将流量转发回到源站。 具体的防护方案如下图: 方案效果 打破地域防护能力的限制,可具有最大300Gpbs的DDoS防护能力。 业务流量使用腾讯云的内网专线进行转发,

  • 腾讯云,DevOps 领导者!

    刚刚,《IDCMarketScape:中国DevOps平台市场厂商评估,2022》正式发布。腾讯云CODING成功入选领导者位置 在战略和能力两大维度国内领先 ?IDC报告指出:腾讯云CODING在一站式DevOps平台领域具有最佳用户体验,对不同规模、不同类型的研发团队均可良好适用,并且在测试、交付、咨询、市场合作等方面,腾讯云CODING沉淀了众多合作伙伴,建立了全面而成熟的生态伙伴体系。  腾讯云   CODINGDevOps 腾讯云推出的面向软件研发团队的一站式研发协作管理平台,从需求提交到产品迭代,从产品设计到代码管理、测试管理、持续集成、制品管理直至部署交付,整套流程均可在一站式平台内完成,降低企业研发管理难度,提升研发效率。目前,CODINGDevOps能够提供企业级公有云服务和私有部署方式,以便满足客户不同场景的开发需求,并提供同城双活、两地三中心高可用容灾能力。客户范围涵盖互联网、金融、政企、工业、运营商、媒体、医疗、教育等各个行业。例如,中化信息联合腾讯云CODINGDevOps打造了新一代数字化研效平台,打通从需求、设计、开发、构建、测试、发布到部署的全流程,

  • Boyer-Moore算法的C++实现

     BM算法-阮一峰的网络日志;  以上给出了通俗易懂的算法讲解,下面给出代码实现,使用的宽字符,这样就不限于英文字母了:(stdafx.h编译不过去就屏蔽掉) //StringSearch_BoyerMoore.cpp:定义控制台应用程序的入口点。 // /* @Date:2016/03/2118:31; @Where:TongzhouDistrictofBeijing; @Author:AlexHong; @Mail:worksdata@163.com; @Reference: http://www.ruanyifeng.com/blog/2013/05/boyer-moore_string_search_algorithm.htmlBM算法-阮一峰的网络日志; */ #include"stdafx.h" #include<sstream> #include<iostream> #include<string> #include<vector> #include<map> usingna

  • [C++] 引用类型&amp;

    引用的方法: 类型&引用名=变量名; 例如: inta=5; int&b=a;复制   引用的规则: 1、引用被创建的同时必须被初始化 2、无null引用,引用必须与合法的存储单元关联 3、一旦引用被初始化,就不能改变引用的关系 4、引用只能引用变量,不能引用常量和表达式   举例: #include<iostream> usingnamespacestd; //使用普通类型交换,失败 voidswap1(inta,intb) { inttmp; tmp=a; a=b; b=tmp; } //使用引用类型交换,和指针功能一样,成功 voidswap2(int&a,int&b) { inttmp; tmp=a; a=b; b=tmp; } intmain(void) { inta=35; //b是a的引用类型,b是a的别名,本质是同一个变量 int&b=a; //a和b的值一样 cout<<"a="<<a<<",b="<<b<<endl;

  • HDU 1176 免费馅饼

    都说天上不会掉馅饼,但有一天gameboy正走在回家的小径上,忽然天上掉下大把大把的馅饼。说来gameboy的人品实在是太好了,这馅饼别处都不掉,就掉落在他身旁的10米范围内。馅饼如果掉在了地上当然就不能吃了,所以gameboy马上卸下身上的背包去接。但由于小径两侧都不能站人,所以他只能在小径上接。由于gameboy平时老呆在房间里玩游戏,虽然在游戏中是个身手敏捷的高手,但在现实中运动神经特别迟钝,每秒种只有在移动不超过一米的范围内接住坠落的馅饼。现在给这条小径如图标上坐标: 为了使问题简化,假设在接下来的一段时间里,馅饼都掉落在0-10这11个位置。开始时gameboy站在5这个位置,因此在第一秒,他只能接到4,5,6这三个位置中其中一个位置上的馅饼。问gameboy最多可能接到多少个馅饼?(假设他的背包可以容纳无穷多个馅饼)  Input输入数据有多组。每组数据的第一行为以正整数n(0<n<100000),表示有n个馅饼掉在这条小径上。在结下来的n行中,每行有两个整数x,T(0<T<100000),表示在第T秒有一个馅饼掉在x点上。同

  • 您认为性能测试工作的目的是什么?做好性能测试工作的关键是什么?

    关键是测试脚本的录制,测试时候测试环境的干净。

  • golang_从终端输入时不输入ENTER读取SPACE

    golang_从终端输入时不输入ENTER读取SPACE 转载注明来源:本文链接来自osnosn的博客,写于2021-11-04. 参考 【从终端输入时不输入ENTER读取SPACE】 【nsf/termbox-go】 转载注明来源:本文链接https://www.cnblogs.com/osnosn/p/15510616.html 来自osnosn的博客https://www.cnblogs.com/osnosn/.

  • sudoku

    [sudoku] 给出一个\(16\times16\)的数独局面,要你填写。 解 考虑搜索,现在给出优化过程 二进制压缩设\(h_i,l_i,J_i\)分别表示每行每列每个16宫格能填的数字,这样就可\("O(3)"\)查询某个位置上能填的数字,修改某个位置上能填的数字。 优化搜索顺序,显然我们要从能够填的数字最少的位置开始填数字,当一个位置不能填数字的时候,return。 优化搜索顺序,显然对于每行每列每个9宫格而言,只要存在某个字母只能填在一个位置,立即填上,继续搜索,如果失败,return,如果存在某个字母不能填在任何一个位置,直接return。 然后超长的码量和常数就可以水过这道题目了。 参考代码: #include<iostream> #include<cstdio> #defineilinline #defineriregister usingnamespacestd; chars[16][17]; inth[16],l[16],J[16],dy[65536],js[65536]; booldfs(int); intmain(){

  • 深入浅出koa洋葱模型

    关于洋葱模型很多人都理解,并且绝大多数人都知道要想保证洋葱模型必须要使用async和await  那么问题来了async和await是用来解决异步编程的,那么当我们调用的下一个中间件不存在异步的时候,是否还需要使用async和await 答案是肯定的,以至于现在很多人只要是写中间件必用async和await那么你是否知道它的运行机制和底层原理的一个合格的开发人员是不是要做到知其然还要知其所以然呢? 我们就拿最为简单的全局异常处理来举例,在异步编程模型中全局异常处理因为函数执行时压栈与出栈队列的关系,往往有些抽象 async function fun() {   try {     await fun1();   } catch (error) {     console.log(5555);   } } async function 

  • Axure 9快捷键大全

    本文列举了AxureRP9中所有的快捷键操作,应该是目前网络上最全的,详细请参考下面目录: 1常用快捷键     2文字样式快捷键     3画布快捷键     4插入对象     5编辑         6Vector      7页面/目录快捷键     8光标模式     9栏目 此部分快捷键为调整栏目视图的快捷键       10发布快捷键     11账户相关快捷键  

  • 策略模式(Strategy Pattern)

    是什么? 怎么用? 在什么情况下用? 例子!     策略模式:   对象有某个行为,但在不同的场景下,改行为有不同的实现算法。   比如:     每个人都要交「个人所得税」,但「在美国交的个人所得税」和「在中国交的个人所得税」有不同的算法。   再比如:     鸭子(所有的鸭子)有翅膀,但木头做的鸭子不会飞,活的鸭子会飞,机械鸭子用动力飞。   使用场景:   1、一个系统有很多类,但这些类的区别仅是它们的行为不同。   2、一个系统需要在几个算法中动态的选择一种。那么这些算法可以包装到一个个具体的算法类中,而这一个个具体的算法类都是一个抽象算法类的子类。   原理:   1、定义一族算法(业务规则,如:鸟的飞行方式、个人所得税的缴税方式)   2、封装每个算法。   3、这些算法之间可以相互替换。 例子: 比如:   设计一个鸭子游戏,游戏中会出现各种鸭子,鸭子类型有木头鸭(不会飞,不会叫)、模型鸭(不会叫,动力飞)、绿头鸭(会飞、会叫)。   Duck类相当于Context,是鸭子的基类,所有的鸭子都继承这个类。   Rubb

  • Windows查看端口占用并结束进程

    进入cmd命令提示符:   netstat-aon|findstr"8080":筛选出端口号为8080的进程信息,找到PID   taskkill-f /pid 17792:强制结束进程 补充:   tasklist|findstr"17792":查看进程号PID为17792的进程     

  • 【原】2014年5月学习进度报告

      一、英语学习 1、使用“拓词”背托福核心词:6天       2、使用纸笔复习之前的单词:9天   一点体会:“拓词”软件确实是一款非常不错的背单词软件,通过让单词的适时反复出现,让大脑在被动的状态下识记单词。但是,长期使用后渐渐发现,能在软件里正确识记的单词却常常在日常场景中忘记词义,也就是单词重现太依赖于软件内部,于是从这个月开始,将重点放在巩固以前学习过的单词上,落实那些似认识又印象模糊的词汇。     二、阅读 《当我谈跑步时,我谈些什么》(村上春树第一本写自己的书,读完后有让自己变成一个跑者的冲动,有笔记) 《重口味心理学》(拼凑出来的一本书,虽能了解一些比较偏门的心理学定义,却没有太深刻的东西,不推荐) 三、OCP考试     5月8日考完052,正在全力准备053,计划6月20日前考完。   四、其他小研究   SignalR:一个开源的asp.net的异步类库,可用于保持服务器与多客户端浏览器的消息同步,典型应用可以开发Chat

  • knative-02-CDC

     

相关推荐

推荐阅读