• go 多线程并发 queue demo


    原文链接:Writing worker queues, in Go

    1.work.go 

    [root@wangjq queue]# cat work.go 
    package main
    
    import "time"
    
    type WorkRequest struct {
            Name  string
            Delay time.Duration
    }

    2.collector.go

    [root@wangjq queue]# cat collector.go
    package main
    
    import (
            "fmt"
            "net/http"
            "time"
    )
    
    // A buffered channel that we can send work requests on.
    var WorkQueue = make(chan WorkRequest, 100)
    
    func Collector(w http.ResponseWriter, r *http.Request) {
            // Make sure we can only be called with an HTTP POST request.
            if r.Method != "POST" {
                    w.Header().Set("Allow", "POST")
                    w.WriteHeader(http.StatusMethodNotAllowed)
                    return
            }
    
            // Parse the delay.
            delay, err := time.ParseDuration(r.FormValue("delay"))
            if err != nil {
                    http.Error(w, "Bad delay value: "+err.Error(), http.StatusBadRequest)
                    return
            }
    
            // Check to make sure the delay is anywhere from 1 to 10 seconds.
            if delay.Seconds() < 1 || delay.Seconds() > 10 {
                    http.Error(w, "The delay must be between 1 and 10 seconds, inclusively.", http.StatusBadRequest)
                    return
            }
    
            // Now, we retrieve the person's name from the request.
            name := r.FormValue("name")
    
            // Just do a quick bit of sanity checking to make sure the client actually provided us with a name.
            if name == "" {
                    http.Error(w, "You must specify a name.", http.StatusBadRequest)
                    return
            }
    
            // Now, we take the delay, and the person's name, and make a WorkRequest out of them.
            work := WorkRequest{Name: name, Delay: delay}
    
            // Push the work onto the queue.
            WorkQueue <- work
            fmt.Println("Work request queued")
    
            // And let the user know their work request was created.
            w.WriteHeader(http.StatusCreated)
            return
    }

    3.worker.go

    [root@wangjq queue]# cat worker.go
    package main
    
    import (
            "fmt"
            "time"
    )
    
    // NewWorker creates, and returns a new Worker object. Its only argument
    // is a channel that the worker can add itself to whenever it is done its
    // work.
    func NewWorker(id int, workerQueue chan chan WorkRequest) Worker {
            // Create, and return the worker.
            worker := Worker{
                    ID:          id,
                    Work:        make(chan WorkRequest),
                    WorkerQueue: workerQueue,
                    QuitChan:    make(chan bool)}
    
            return worker
    }
    
    type Worker struct {
            ID          int
            Work        chan WorkRequest
            WorkerQueue chan chan WorkRequest
            QuitChan    chan bool
    }
    
    // This function "starts" the worker by starting a goroutine, that is
    // an infinite "for-select" loop.
    func (w *Worker) Start() {
            go func() {
                    for {
                            // Add ourselves into the worker queue.
                            w.WorkerQueue <- w.Work
    
                            select {
                            case work := <-w.Work:
                                    // Receive a work request.
                                    fmt.Printf("worker%d: Received work request, delaying for %f seconds
    ", w.ID, work.Delay.Seconds())
    
                                    time.Sleep(work.Delay)
                                    fmt.Printf("worker%d: Hello, %s!
    ", w.ID, work.Name)
    
                            case <-w.QuitChan:
                                    // We have been asked to stop.
                                    fmt.Printf("worker%d stopping
    ", w.ID)
                                    return
                            }
                    }
            }()
    }
    
    // Stop tells the worker to stop listening for work requests.
    //
    // Note that the worker will only stop *after* it has finished its work.
    func (w *Worker) Stop() {
            go func() {
                    w.QuitChan <- true
            }()
    }

    4.dispatcher.go

    [root@wangjq queue]# cat dispatcher.go
    package main
    
    import "fmt"
    
    var WorkerQueue chan chan WorkRequest
    
    func StartDispatcher(nworkers int) {
            // First, initialize the channel we are going to but the workers' work channels into.
            WorkerQueue = make(chan chan WorkRequest, nworkers)
    
            // Now, create all of our workers.
            for i := 0; i < nworkers; i++ {
                    fmt.Println("Starting worker", i+1)
                    worker := NewWorker(i+1, WorkerQueue)
                    worker.Start()
            }
    
            go func() {
                    for {
                            select {
                            case work := <-WorkQueue:
                                    fmt.Println("Received work requeust")
                                    go func() {
                                            worker := <-WorkerQueue
    
                                            fmt.Println("Dispatching work request")
                                            worker <- work
                                    }()
                            }
                    }
            }()
    }

    5.main.go

    [root@wangjq queue]# cat main.go
    package main
    
    import (
            "flag"
            "fmt"
            "net/http"
    )
    
    var (
            NWorkers = flag.Int("n", 4, "The number of workers to start")
            HTTPAddr = flag.String("http", "127.0.0.1:8000", "Address to listen for HTTP requests on")
    )
    
    func main() {
            // Parse the command-line flags.
            flag.Parse()
    
            // Start the dispatcher.
            fmt.Println("Starting the dispatcher")
            StartDispatcher(*NWorkers)
    
            // Register our collector as an HTTP handler function.
            fmt.Println("Registering the collector")
            http.HandleFunc("/work", Collector)
    
            // Start the HTTP server!
            fmt.Println("HTTP server listening on", *HTTPAddr)
            if err := http.ListenAndServe(*HTTPAddr, nil); err != nil {
                    fmt.Println(err.Error())
            }
    }

    6.编译

    [root@wangjq queue]# go build -o queued *.go

    7.运行

    [root@wangjq queue]# ./queued -n 5
    Starting the dispatcher
    Starting worker 1
    Starting worker 2
    Starting worker 3
    Starting worker 4
    Starting worker 5
    Registering the collector
    HTTP server listening on 127.0.0.1:8000

    8.测试

    [root@wangjq ~]# for i in {1..3}; do curl localhost:8000/work -d name=$USER -d delay=$(expr $i % 11)s; done

    9.效果

    [root@wangjq queue]# ./queued -n 5
    Starting the dispatcher
    Starting worker 1
    Starting worker 2
    Starting worker 3
    Starting worker 4
    Starting worker 5
    Registering the collector
    HTTP server listening on 127.0.0.1:8000
    Work request queued
    Received work requeust
    Dispatching work request
    worker1: Received work request, delaying for 1.000000 seconds
    Work request queued
    Received work requeust
    Dispatching work request
    worker2: Received work request, delaying for 2.000000 seconds
    Work request queued
    Received work requeust
    Dispatching work request
    worker4: Received work request, delaying for 3.000000 seconds
    worker1: Hello, root!
    worker2: Hello, root!
    worker4: Hello, root!
  • 相关阅读:
    Thread+Handler 线程 消息循环(转载)
    android开发之Fragment加载到一个Activity中
    Android应用程序框架之无边界设计意图
    windows系统下安装MySQL
    Java 性能优化技巧集锦
    功能完善的Java连接池调用实例
    Unicode 与 UTF 字符标准
    java内存配置
    Java Map 简介
    nginx 学习笔记(9) 配置HTTPS服务器--转载
  • 原文地址:https://www.cnblogs.com/wangjq19920210/p/11526946.html
Copyright © 2020-2023  润新知