在进行工作池的代码练习时候,我发现了一个有趣的事情,首先看下面一段代码:

package main

import "fmt"
import "time" func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
fmt.Println("worker", id, "processing job", j)
time.Sleep(time.Second)
results <- j * 2
}
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
for j := 1; j <= 9; j++ {
jobs <- j
}
close(jobs)
for a := 1; a <= 9; a++ {
<-results
}
}

  

上面代码运行结果是下面这样的,会发现3个工人,平均分配了9个工作,每人有3个

worker 3 processing job 1
worker 2 processing job 3
worker 1 processing job 2
worker 3 processing job 4
worker 1 processing job 5
worker 2 processing job 6
worker 1 processing job 8
worker 2 processing job 7
worker 3 processing job 9

  

但是,如果将代码改造成下面这样,去掉了工作的时间等待:

package main

import "fmt"

func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
fmt.Printf("I am %d working at jobs %d\n", id, j)
results <- j * 2
}
} func main() {
jobs := make(chan int, 10)
results := make(chan int, 10)
for i := 1; i < 4; i++ {
go worker(i, jobs, results)
}
for k := 1; k < 10; k++ {
jobs <- k
}
for v := 1; v < 10; v++ {
<-results
}
}

  

那么运行结果变成了下面这样:

I am 3 working at jobs 1
I am 3 working at jobs 4
I am 3 working at jobs 5
I am 3 working at jobs 6
I am 3 working at jobs 7
I am 3 working at jobs 8
I am 3 working at jobs 9
I am 1 working at jobs 2
I am 2 working at jobs 3

  

你会发现,第三个工人做了9件工作里面的7件,剩余两个工人闲下来了。经过代码的分析发现,这个例子的逻辑是,先将9件工作全部放在jobs通道中,然后再由工人从jobs通道里取任务,做完后返回结果。但是如果某个工人做的快,还没等剩余的工人取任务时候就完成了,那他就会做很多工作,如果在实际开发中,不考虑类似问题的话,会造成性能浪费,任务分配不平均的问题

经过思考,我决定改变任务分配方式,不能一股脑的将任务全部分配下去,应该做完一件,再分配一件,这样来避免任务分配问题,我在代码中,增加了一个isTrue通道,当第一个任务做完后,将结果发送给isTrue通道,然后任务分配方拿到isTrue里的值后再分配下一个任务,改造后的代码如下:

package main

import "fmt"

func worker(id int, jobs <-chan int, results chan<- int, isTrue chan<- bool) {
for j := range jobs {
fmt.Printf("I am %d working at jobs %d\n", id, j)
results <- j * 2
isTrue <- true
}
} func main() {
jobs := make(chan int, 10)
results := make(chan int, 10)
isTrue := make(chan bool)
for i := 1; i < 4; i++ {
go worker(i, jobs, results, isTrue)
}
for k := 1; k < 10; k++ {
jobs <- k
<-isTrue
}
for v := 1; v < 10; v++ {
<-results
}
}

  

代码运行结果如下:

I am 3 working at jobs 1
I am 1 working at jobs 2
I am 2 working at jobs 3
I am 3 working at jobs 4
I am 1 working at jobs 5
I am 2 working at jobs 6
I am 3 working at jobs 7
I am 1 working at jobs 8
I am 2 working at jobs 9

  

以上就解决了任务分配问题。当然,我这种方式还是有缺点的,因为增加了分配任务的时间,会让任务完成总时间增大,在实际业务中,肯定还会有更加完美的解决方案

003_对go语言中的工作池代码练习的一些思考和改进的更多相关文章

  1. 034_go语言中的工作池

    代码演示 package main import "fmt" import "time" func worker(id int, jobs <-chan ...

  2. node-mysql中的连接池代码学习

    node-mysql是一个node.js下的mysql驱动,前段时间在处理连接池的问题上遇到了连接不释放的疑难杂症,虽已解决,但仍需总结经验避免下次重蹈覆辙.下面是node-mysql中的连接池的部分 ...

  3. 006_go语言中的互斥锁的作用练习与思考

    在go语言基本知识点中,我练习了一下互斥锁,感觉还是有点懵逼状,接下来为了弄懂,我再次进行了一些尝试,以下就是经过我的尝试后得出的互斥锁的作用. 首先还是奉上我改造后的代码: package main ...

  4. [Go]TCP服务中增加消息队列与工作池

    之前的处理中每一个连接都会创建一个主groutine , 每个连接中的主groutine中创建出读groutine 和写groutine 每个连接处理业务再单独开出一个groutine ,这样如果有1 ...

  5. go语言从例子开始之Example33.工作池

    在这个例子中,我们将看到如何使用 Go 协程和通道实现一个工作池 . Example: package main import "fmt" import "time&qu ...

  6. Java语言中的这些知识点有没有用过,工作中有没有入过这些坑?

    在Java语言中,有一些相对生僻的知识,平时用的机会可能不是很多,但如果不了解不掌握这些知识点的话,也可能会掉入陷阱之中,今天我们就来初步梳理一下: 1. goto是java语言中的关键字. &quo ...

  7. C语言实现简单线程池(转-Newerth)

    有时我们会需要大量线程来处理一些相互独立的任务,为了避免频繁的申请释放线程所带来的开销,我们可以使用线程池.下面是一个C语言实现的简单的线程池. 头文件: 1: #ifndef THREAD_POOL ...

  8. .NET管道应用——工作池

    名词解释 工作池:一组等待任务分配的线程.一旦完成了所分配的任务,这些线程可继续等待任务的分配. .NET管道:命名空间System.Threading.Channels中的Channel和Chann ...

  9. Go语言中的并发编程

    并发是编程里面一个非常重要的概念,Go语言在语言层面天生支持并发,这也是Go语言流行的一个很重要的原因. Go语言中的并发编程 并发与并行 并发:同一时间段内执行多个任务(你在用微信和两个女朋友聊天) ...

随机推荐

  1. 数据可视化之powerBI入门(五)PowerQuery,支持从多种源导入数据

    PowerBI的强大绝不仅是最后生成炫酷的可视化报告,她在第一步数据获取上就显示出了强大的威力,利用Power Query 的强大数据处理功能,几乎可以从任何来源.任何结构.任何形式上获取数据 htt ...

  2. Linux08 /Docker

    Linux08 /Docker 目录 Linux08 /Docker 1. docker简介/安装 2. Docker镜像加速器的设置 3. 核心三要素 镜像仓库/Registry 镜像/Image: ...

  3. Python并发编程04 /多线程、生产消费者模型、线程进程对比、线程的方法、线程join、守护线程、线程互斥锁

    Python并发编程04 /多线程.生产消费者模型.线程进程对比.线程的方法.线程join.守护线程.线程互斥锁 目录 Python并发编程04 /多线程.生产消费者模型.线程进程对比.线程的方法.线 ...

  4. Java实现导入导出Excel:POI和EasyExcel

    文章与CSDN同步,欢迎访问:https://blog.csdn.net/qq_40280582/article/details/107300081 代码地址:https://gitee.com/il ...

  5. 06-Python元组,列表,字典,集合数据结构

    一.简介 数据结构是我们用来处理一些数据的结构,用来存储一系列的相关数据. 在python中,有列表,元组,字典和集合四种内建的数据结构. 二.列表 用于存储任意数目.任意类型的数据集合.列表是内置可 ...

  6. 1.对Java平台的理解。“Java是解释执行”对吗

    Java本身是一种面向对象的语言,最显著的特性有两个方面,一是所谓的“书写一次,到处运行”,能够非常容易地获得跨平台能力: 另外就是垃圾收集(GC),Java通过垃圾收集器(Garbage Colle ...

  7. bzoj2456mode

    bzoj2456mode 题意: 给你一个n个数的数列,求出现次数超过n div 2的数(只有1个). 题解: 注意空间只有1M,显然不能开数组.用两个变量,一个存“当前数”,另一个存“当前数”的个数 ...

  8. 一、Python系列——函数的应用之名片管理系统

    card_list = [] def main_desk(): print('*'*50) print('欢迎使用[名片管理系统]V1.0') print('1.新建名片') print('2.显示全 ...

  9. 基于Python的HTTP接口自动化测试框架实现

    今天我们来讲一下基于Python的HTTP接口自动化测试框架的实现,范例如下: 一.测试需求描述 对服务后台一系列的http接口功能测试. 输入:根据接口描述构造不同的参数输入值 输出:XML文件 e ...

  10. 设计模式:memento模式

    目的:在不破坏系统封装性的前提下,记录系统每一步的状态,可以做到状态回退和前进 方法: 定义一个数据类,保存所有相关数据 定义一个管理类,提供保存和恢复的接口 具体操作类调用管理类的保存和恢复接口 例 ...