【问题标题】:How to pass time.Duration type to a go function?如何将 time.Duration 类型传递给 go 函数?
【发布时间】:2018-08-12 15:29:45
【问题描述】:

我正在学习 GOLANG,尤其是它的并发能力。

已尝试进一步开发其中一个 worker_pool 示例,以便每个工作人员接收一个作业 ID 和一个作业负载,以作业的随机持续时间表示。

time.sleep 命令使用持续时间来等待分配的纳秒数,这是随机计算的。

代码看起来像这样...

//worker_pool improved example

package main

import "fmt"
import "time"
import "math/rand"

// Here's the worker, of which we'll run several
// concurrent instances. These workers will receive
// work on the `jobs` channel and send the corresponding
// results on `results`. We'll sleep a random number of seconds between
// 1 and 5 to simulate an expensive task.
func worker(id int, jobs <-chan int, loads <-chan time.Duration, results chan<- int) {
   for j := range jobs {
        fmt.Println("worker", id, "started  job", j, time.Now())
        time.Sleep(loads*time.Second)  
        fmt.Println("worker", id, "finished job", j, time.Now())
        results <- j * 2
    }
}

func main() {

    // In order to use our pool of workers we need to send
    // them work and collect their results. We make 2
    // channels for this.
    jobs := make(chan int)
    loads := make(chan time.Duration)
    results := make(chan int)

    // This starts up 3 workers, initially blocked
    // because there are no jobs yet.
    for w := 1; w <= 3; w++ {
        go worker(w, jobs, results)
    }

    // Here we send 24 `jobs` and then `close` that
    // channel to indicate that's all the work we have.
    for j := 1; j <= 24; j++ {
        jobs <- j
        r := rand.New(rand.NewSource(99))
        load := r.Int63n(5000000)
        loads <- load
    }
    close(jobs)
    close(loads)


    // Finally we collect all the results of the work.
    for a := 1; a <= 24; a++ {
        <-results
    }
}

我不断收到此错误消息...

prog.go:18:33: 无法将负载(类型

prog.go:36:18: 调用 worker 时参数不足 有 (int, chan int, chan int) 想要 (int,

prog.go:45:15: 不能在发送中使用负载(int64 类型)作为 int 类型

我做错了什么?

【问题讨论】:

  • 您正在使用来自loads 通道的值,就好像它们是整数一样,但它们实际上是time.Duration 类型。使用Nanoseconds() 方法获取一个float64 的duration,然后将其转换为整数。您也没有在 go worker(w, jobs, results) 调用中传递足够的参数。
  • @teolandon:类型time.Duration 是一个整数:type Duration int64。您的评论没有意义。
  • @peterSO 你是对的,它的 int64 整数表示只是纳秒计数,所以我所说的都是多余的。第 18 行的真正问题是通道被当作整数使用。

标签: function go concurrency duration channels


【解决方案1】:

即使你修复了你的编译错误,你仍然有问题。

//worker_pool improved example

package main

import "fmt"
import "time"
import "math/rand"

// Here's the worker, of which we'll run several
// concurrent instances. These workers will receive
// work on the `jobs` channel and send the corresponding
// results on `results`. We'll sleep a random number of seconds between
// 1 and 5 to simulate an expensive task.
func worker(id int, jobs <-chan int, loads <-chan time.Duration, results chan<- int) {
    for j := range jobs {
        fmt.Println("worker", id, "started  job", j, time.Now())
        time.Sleep(<-loads * time.Second)
        fmt.Println("worker", id, "finished job", j, time.Now())
        results <- j * 2
    }
}

func main() {

    // In order to use our pool of workers we need to send
    // them work and collect their results. We make 2
    // channels for this.
    jobs := make(chan int)
    loads := make(chan time.Duration)
    results := make(chan int)

    // This starts up 3 workers, initially blocked
    // because there are no jobs yet.
    for w := 1; w <= 3; w++ {
        go worker(w, jobs, loads, results)
    }

    // Here we send 24 `jobs` and then `close` that
    // channel to indicate that's all the work we have.
    for j := 1; j <= 24; j++ {
        jobs <- j
        r := rand.New(rand.NewSource(99))
        load := time.Duration(r.Int63n(5000000))
        loads <- load
    }
    close(jobs)
    close(loads)

    // Finally we collect all the results of the work.
    for a := 1; a <= 24; a++ {
        <-results
    }
}

游乐场:https://play.golang.org/p/tVdlKFHunKN

输出:

worker 3 started  job 1 2009-11-10 23:00:00 +0000 UTC m=+0.000000001
worker 1 started  job 2 2009-11-10 23:00:00 +0000 UTC m=+0.000000001
worker 2 started  job 3 2009-11-10 23:00:00 +0000 UTC m=+0.000000001
worker 1 finished job 2 2009-12-27 17:05:41 +0000 UTC m=+4039541.000000001
worker 3 finished job 1 2009-12-27 17:05:41 +0000 UTC m=+4039541.000000001
worker 2 finished job 3 2009-12-27 17:05:41 +0000 UTC m=+4039541.000000001
fatal error: all goroutines are asleep - deadlock!

【讨论】:

    【解决方案2】:

    确实是代码有问题。

    我创建的频道没有缓冲。我为作业和结果通道添加了 100 个缓冲区(每个原始示例),程序运行良好。

    //worker_pool improved example
    
    package main
    
    import "fmt"
    import "time"
    import "math/rand"
    
    func worker(id int, jobs <-chan int, loads <-chan time.Duration, results chan<- int) {
        for j := range jobs {
            before := time.Now()
            fmt.Println("worker", id, "started  job", j)
            time.Sleep(<-loads)
            after := time.Now()
            fmt.Println("worker", id, "finished job", j, "in", after.Sub(before))
            results <- j
        }
    }
    
    func main() {
    
        jobs := make(chan int, 100) // Buffered channel
        loads := make(chan time.Duration)
        results := make(chan int, 100) // Buffered channel
    
        for w := 1; w <= 3; w++ {
            go worker(w, jobs, loads, results)
        }
    
        for j := 1; j <= 24; j++ {
            jobs <- j
            r := rand.New(rand.NewSource(int64(j*10)))
            loads <- time.Duration(r.Int63n(500000000)) // In nano seconds
        }
        close(jobs)
        close(loads)
    
        for a := 1; a <= 24; a++ {
            <-results
        }
    }
    

    游乐场:https://play.golang.org/p/bz-JIkD1OoG

    我还在习惯随机生成器的逻辑。它每次都返回完全相同的数字,给定一个特定的种子,在我看来这打败了随机性的概念。

    部分结果...

    worker 3 started  job 1
    worker 1 started  job 2
    worker 2 started  job 3
    worker 1 finished job 2 in 168.00641ms
    worker 1 started  job 4
    worker 3 finished job 1 in 205.826435ms
    worker 3 started  job 5
    worker 3 finished job 5 in 160.909863ms
    worker 3 started  job 6
    worker 2 finished job 3 in 381.707665ms
    

    【讨论】:

    • “它每次都返回完全相同的数字,给定一个特定的种子,在我看来这打败了随机性的概念。”这才是重点。能够为测试目的生成可重现的伪随机序列是件好事。关键是以不可预知的方式生成种子;使用计算机的微秒时钟是执行此操作的常用方法
    猜你喜欢
    • 1970-01-01
    • 2015-01-02
    • 2016-02-28
    • 1970-01-01
    • 2017-07-19
    • 1970-01-01
    • 2019-06-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多