草庐IT

go - 关于 Go 中 channel 方向和阻塞的混淆

coder 2023-07-02 原文

在函数定义中,如果 channel 是没有方向的参数,它是否必须发送或接收某些东西?

func makeRequest(url string, ch chan<- string, results chan<- string) {
    start := time.Now()

    resp, err := http.Get(url)
    defer resp.Body.Close()
    if err != nil {
        fmt.Printf("%v", err)
    }

    resp, err = http.Post(url, "text/plain", bytes.NewBuffer([]byte("Hey")))
    defer resp.Body.Close()

    secs := time.Since(start).Seconds()

    if err != nil {
        fmt.Printf("%v", err)
    }
    // Cannot move past this.
    ch <- fmt.Sprintf("%f", secs) 
    results <- <- ch
}

func MakeRequestHelper(url string, ch chan string, results chan string, iterations int) {
    for i := 0; i < iterations; i++ {
        makeRequest(url, ch, results)
    }
    for i := 0; i < iterations; i++ {
        fmt.Println(<-ch)
    }
}

func main() {
    args := os.Args[1:]
    threadString := args[0]
    iterationString := args[1]
    url := args[2]
    threads, err := strconv.Atoi(threadString)
    if err != nil {
        fmt.Printf("%v", err)
    }
    iterations, err := strconv.Atoi(iterationString)
    if err != nil {
        fmt.Printf("%v", err)
    }

    channels := make([]chan string, 100)
    for i := range channels {
        channels[i] = make(chan string)
    }

    // results aggregate all the things received by channels in all goroutines
    results := make(chan string, iterations*threads)

    for i := 0; i < threads; i++ {
        go MakeRequestHelper(url, channels[i], results, iterations)

    }

    resultSlice := make([]string, threads*iterations)
    for i := 0; i < threads*iterations; i++ {
        resultSlice[i] = <-results
    }
}

在上面的代码中,

ch <- or <-results

似乎阻塞了执行 makeRequest 的每个 goroutine。

我是 Go 并发模型的新手。我知道发送到 channel 和从 channel 接收会阻塞,但发现很难阻止此代码中的内容。

最佳答案

我不太确定你在做什么......看起来真的很复杂。我建议您阅读有关如何使用 channel 的信息。

https://tour.golang.org/concurrency/2

也就是说,您的代码中发生了太多事情,因此将其简化为更简单的内容要容易得多。 (可以进一步简化)。我留下了评论以理解代码。

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "sync"
    "time"
)

// using structs is a nice way to organize your code
type Worker struct {
    wg        sync.WaitGroup
    semaphore chan struct{}
    result    chan Result
    client    http.Client
}

// group returns so that you don't have to send to many channels
type Result struct {
    duration float64
    results  string
}

// closing your channels will stop the for loop in main
func (w *Worker) Close() {
    close(w.semaphore)
    close(w.result)
}

func (w *Worker) MakeRequest(url string) {
    // a semaphore is a simple way to rate limit the amount of goroutines running at any single point of time
    // google them, Go uses them often
    w.semaphore <- struct{}{}
    defer func() {
        w.wg.Done()
        <-w.semaphore
    }()

    start := time.Now()

    resp, err := w.client.Get(url)
    if err != nil {
        log.Println("error", err)
        return
    }
    defer resp.Body.Close()

    // don't have any examples where I need to also POST anything but the point should be made
    // resp, err = http.Post(url, "text/plain", bytes.NewBuffer([]byte("Hey")))
    // if err != nil {
    // log.Println("error", err)
    // return
    // }
    // defer resp.Body.Close()

    secs := time.Since(start).Seconds()

    b, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Println("error", err)
        return
    }
    w.result <- Result{duration: secs, results: string(b)}
}

func main() {
    urls := []string{"https://facebook.com/", "https://twitter.com/", "https://google.com/", "https://youtube.com/", "https://linkedin.com/", "https://wordpress.org/",
        "https://instagram.com/", "https://pinterest.com/", "https://wikipedia.org/", "https://wordpress.com/", "https://blogspot.com/", "https://apple.com/",
    }

    workerNumber := 5
    worker := Worker{
        semaphore: make(chan struct{}, workerNumber),
        result:    make(chan Result),
        client:    http.Client{Timeout: 5 * time.Second},
    }

    // use sync groups to allow your code to wait for
    // all your goroutines to finish
    for _, url := range urls {
        worker.wg.Add(1)
        go worker.MakeRequest(url)
    }

    // by declaring wait and close as a seperate goroutine
    // I can get to the for loop below and iterate on the results
    // in a non blocking fashion
    go func() {
        worker.wg.Wait()
        worker.Close()
    }()

    // do something with the results channel
    for res := range worker.result {
        fmt.Printf("Request took %2.f seconds.\nResults: %s\n\n", res.duration, res.results)
    }
}

关于go - 关于 Go 中 channel 方向和阻塞的混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46480918/

有关go - 关于 Go 中 channel 方向和阻塞的混淆的更多相关文章

  1. ruby-on-rails - 关于 Ruby 的一般问题 - 2

    我在我的rails应用程序中安装了来自github.com的acts_as_versioned插件,但有一段代码我不完全理解,我希望有人能帮我解决这个问题class_eval我知道block内的方法(或任何它是什么)被定义为类内的实例方法,但我在插件的任何地方都找不到定义为常量的CLASS_METHODS,而且我也不确定是什么here,并且有问题的代码从lib/acts_as_versioned.rb的第199行开始。如果有人愿意告诉我这里的内幕,我将不胜感激。谢谢-C 最佳答案 这是一个异端。http://en.wikipedia

  2. ruby - 我怎样才能更好地了解/了解更多关于 Ruby 的知识? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我最近开始学习Ruby,这是我的第一门编程语言。我对语法感到满意,并且我已经完成了许多只教授相同基础知识的教程。我已经写了一些小程序(包括我自己的数组排序方法,在有人告诉我谷歌“冒泡排序”之前我认为它非常聪明),但我觉得我需要尝试更大更难的东西来理解更多关于Ruby.关于如何执行此操作的任何想法?

  3. ruby - 关于 Ruby 中 Dir[] 和 File.join() 的混淆 - 2

    我在Ruby中遇到了一个关于Dir[]和File.join()的简单程序,blobs_dir='/path/to/dir'Dir[File.join(blobs_dir,"**","*")].eachdo|file|FileUtils.rm_rf(file)ifFile.symlink?(file)我有两个困惑:首先,File.join(@blobs_dir,"**","*")中的第二个和第三个参数是什么意思?其次,Dir[]在Ruby中有什么用?我只知道它等价于Dir.glob(),但是,我对Dir.glob()确实不是很清楚。 最佳答案

  4. ruby-on-rails - Textmate 'Go to symbol' 相当于 Vim - 2

    在Railcasts上,我注意到一个非常有趣的功能“转到符号”窗口。它像Command-T一样工作,但显示当前文件中可用的类和方法。如何在vim中获取它? 最佳答案 尝试:helptags有各种程序和脚本可以生成标记文件。此外,标记文件格式非常简单,因此很容易将sed(1)或类似的脚本组合在一起,无论您使用何种语言,它们都可以生成标记文件。轻松获取标记文件(除了下载生成器之外)的关键在于格式化样式而不是实际解析语法。 关于ruby-on-rails-Textmate'Gotosymbol

  5. elasticsearch源码关于TransportSearchAction【阶段三】 - 2

    1.回顾.TransportServicepublicclassTransportServiceextendsAbstractLifecycleComponentTransportService:方法:1publicfinalTextendsTransportResponse>voidsendRequest(finalTransport.Connectionconnection,finalStringaction,finalTransportRequestrequest,finalTransportRequestOptionsoptions,TransportResponseHandlerT>

  6. 关于Qt程序打包后运行库依赖的常见问题分析及解决方法 - 2

    目录一.大致如下常见问题:(1)找不到程序所依赖的Qt库version`Qt_5'notfound(requiredby(2)CouldnotLoadtheQtplatformplugin"xcb"in""eventhoughitwasfound(3)打包到在不同的linux系统下,或者打包到高版本的相同系统下,运行程序时,直接提示段错误即segmentationfault,或者Illegalinstruction(coredumped)非法指令(4)ldd应用程序或者库,查看运行所依赖的库时,直接报段错误二.问题逐个分析,得出解决方法:(1)找不到程序所依赖的Qt库version`Qt_5'

  7. ruby - IO::EAGAINWaitReadable:资源暂时不可用 - 读取会阻塞 - 2

    当我尝试使用“套接字”库中的方法“read_nonblock”时出现以下错误IO::EAGAINWaitReadable:Resourcetemporarilyunavailable-readwouldblock但是当我通过终端上的IRB尝试时它工作正常如何让它读取缓冲区? 最佳答案 IgetthefollowingerrorwhenItrytousethemethod"read_nonblock"fromthe"socket"library当缓冲区中的数据未准备好时,这是预期的行为。由于异常IO::EAGAINWaitReadab

  8. ruby - RVM Gemsets 和 Ruby Gemfile 混淆 - 2

    请有人帮助我了解ruby​​应用程序如何管理应用程序的gemfile和rvmgemsets。如果我当前使用的是Gemset,安装了一堆gem,并且我的gemfile中也有gems,那么Ruby应用程序是使用gemfile中的gem还是应用程序的gemset中的gem? 最佳答案 要理解这一点,您需要退后一步,了解ruby​​gems的一般工作原理。让我们从一个没有rvm或Gemfile的系统开始。当您通过“geminstall”安装gem时,它会进入系统gem位置。每当您编写ruby​​脚本并需要gem时,它就会从那里获取。现在假设

  9. ruby - 如何使用 ruby​​ fibers 避免阻塞 IO - 2

    我需要将目录中的一堆文件上传到S3。由于上传所需的90%以上的时间都花在了等待http请求完成上,所以我想以某种方式同时执行其中的几个。Fibers能帮我解决这个问题吗?它们被描述为解决此类问题的一种方法,但我想不出在http调用阻塞时我可以做任何工作的任何方法。有什么方法可以在没有线程的情况下解决这个问题? 最佳答案 我没有使用1.9中的纤程,但是1.8.6中的常规线程可以解决这个问题。尝试使用队列http://ruby-doc.org/stdlib/libdoc/thread/rdoc/classes/Queue.html查看文

  10. ruby - 关于 Ruby/ChefSpec 编码风格的反馈 - 2

    我是Ruby的新手,但过去两周我一直在对Chef测试进行大量研究。该测试使用ChefSpec和Fauxhai,但它看起来不是很“像ruby”,我希望社区能给我一些编码风格的建议。有没有更好的方法来编写这样的嵌套循环?Recipe/foo/recipes/default.rbpackage"foo"doaction:installendRecipe/foo/spec/default_spec.rbrequire'chefspec'describe'foo::default'doplatforms={"debian"=>['6.0.5'],"ubuntu"=>['12.04','10.04

随机推荐