Go one million level Concurrency in Practice

Foreword

Based Golang and traditional OS processes and threads of different, complicated by the Go language is based on concurrent user mode, this concurrent manner becomes very lightweight, it can easily run tens of thousands of concurrent logic.

Go one kind of concurrency concurrency model belongs to CSP implementation, the core concept of concurrency model CSP is: "Do not communicate through shared memory, but should pass
through to shared memory communication." This is achieved in the Go language is Goroutine and Channel.

Thread Pool

  • job is a task request
  • a worker thread
  • worker pool is a thread pool
    Here Insert Picture Description

Code

Job.Go

Task interface

// Job接口 含一个do方法,实现该接口,即为一个请求任务
type Job interface {
	Do()
}

worker.go

Thread

// 工作线程结构,里面是一个管道,放多个请求任务
type Worker struct {
	JobQueue chan Job
}

// 类似构造函数,返回一个工作线程
func NewWorker() Worker {
	return Worker{JobQueue: make(chan Job)}
}

// 工作线程的成员函数,处理请求
// 形参wq是一个工作队列
// 调用之后,会起一个线程,无限循环,取出任务,放到线程池中  ???
func (w Worker) Run(wq chan chan Job) {
	go func() {
		for {
			wq <- w.JobQueue
			select {
			case job := <-w.JobQueue:
				job.Do()
			}
		}
	}()
}

workerpool.go

Thread Pool

// 线程池
// 线程数、任务队列、装任务队列的管道
type WorkerPool struct {
	workerlen   int
	JobQueue    chan Job
	WorkerQueue chan chan Job
}

// 线程池的构造函数
func NewWorkerPool(workerlen int) *WorkerPool {
	return &WorkerPool{
		workerlen:   workerlen,
		JobQueue:    make(chan Job),
		WorkerQueue: make(chan chan Job, workerlen),
	}
}

// 线程池的成员函数
// 先打印初始化
// 根据工人池的长度,循环构造n个工作线程,然后调用工作线程的Run函数,即:把任务放到线程池中,然后处理这个线程的任务请求
// 开一个协程,一直循环,任务队列中取出任务,如果有,则看工作队列是否有空余线程,如果有,则工作队列中,取出一个工作协程,处理job请求
func (wp *WorkerPool) Run() {
	fmt.Println("初始化worker")

	// 初始化工作线程
	for i := 0; i < wp.workerlen; i++ {
		worker := NewWorker()
		worker.Run(wp.WorkerQueue)
	}

	// 循环获取可⽤用的工作线程
	go func() {
		for {
			select {
			case job := <-wp.JobQueue:  // 管道取出任务
				worker := <-wp.WorkerQueue // 取出空余线程
				worker <- job  // 处理任务
			}
		}
	}()
}

main.go

The main function

package main

import (
	"fmt"
	"runtime"
	"time"
)

// 分数结构——打印显示用
type Score struct {
	Num int
}

// 分数结构实现了Job接口————即打印自己 然后睡眠2s,即有一个score的请求任务,需要打印自己
func (s *Score) Do() {
	fmt.Println("num:", s.Num)
	time.Sleep(time.Second)
}

func main() {
	//num := 100 * 100 * 20
	num := 1
	// debug.SetMaxThreads(1000) //设置最⼤大线程数
	// 注册⼯工作池,传⼊入任务
	// 参数1 worker并发个数

	// 长度为20w的工作池
	p := NewWorkerPool(num)

	// 先运行 挂起
	p.Run()

	// 创建一亿个分数对象,然后丢进工作池的管道
	//datanum := 100 * 100 * 100 * 100
	datanum := 1
	go func() {
		for i := 1; i <= datanum; i++ {
			sc := &Score{Num: i}
			p.JobQueue <- sc
		}
	}()

	// 每隔2秒打印目前的协程数
	for {
		fmt.Println("runtime.NumGoroutine() :", runtime.NumGoroutine())
		time.Sleep(2 * time.Second)
	}
}

Published 41 original articles · won praise 26 · views 8088

Guess you like

Origin blog.csdn.net/weixin_44879611/article/details/104950858