登录
首页 >  Golang >  Go问答

如何使该程序线程安全,通道是否是最佳实现,如果是,如何实现?

来源:stackoverflow

时间:2024-02-27 20:06:24 333浏览 收藏

本篇文章主要是结合我之前面试的各种经历和实战开发中遇到的问题解决经验整理的,希望这篇《如何使该程序线程安全,通道是否是最佳实现,如果是,如何实现?》对你有很大帮助!欢迎收藏,分享给更多的需要的朋友学习~

问题内容

我正在使用golang,我正在尝试使这个程序线程安全。它接受一个数字作为参数(这是要启动的消费者任务的数量),从输入中读取行,并累积字数。我希望线程是安全的(但我不希望它只是锁定所有内容,它需要高效)我应该使用通道吗?我该怎么做?

package main

import (
    "bufio"
    "fmt"
    "log"
    "os"
    "sync"
)

// Consumer task to operate on queue
func consumer_task(task_num int) {
    
    fmt.Printf("I'm consumer task #%v ", task_num)
    fmt.Println("Line being popped off queue: " + queue[0])

    queue = queue[1:]

}

// Initialize queue
var queue = make([]string, 0)

func main() {

    // Initialize wait group 
    var wg sync.WaitGroup

    // Get number of tasks to run from user
    var numof_tasks int
    fmt.Print("Enter number of tasks to run: ")
    fmt.Scan(&numof_tasks)
    
    // Open file
    file, err := os.Open("test.txt")
    if err != nil {
        log.Fatal(err)
    }

    defer file.Close()

    // Scanner to scan the file
    scanner := bufio.NewScanner(file)
    if err := scanner.Err(); err != nil {
        log.Fatal(err)
    }

    // Loop through each line in the file and append it to the queue
    for scanner.Scan() {
        line := scanner.Text()  
        queue = append(queue, line)
    }

    // Start specified # of consumer tasks
    for i := 1; i <= numof_tasks; i++ {
        wg.Add(1)
        go func(i int) { 
            consumer_task(i) 
            wg.Done()
        }(i)
    }

    wg.Wait()
    fmt.Println("All done")
    fmt.Println(queue)
}

正确答案


切片 queue 上存在数据争用。并发 goroutine,当从队列头部弹出元素时,通过 sync.mutex 锁以受控方式执行此操作。或者使用通道来管理工作项的“队列”。

要将您所拥有的内容转换为使用通道,请更新工作线程以将输入通道作为队列 - 并在通道上进行范围,以便每个工作线程可以处理多个任务:

func consumer_task(task_num int, ch <-chan string) {

    fmt.printf("i'm consumer task #%v\n", task_num)
    for item := range ch {
        fmt.printf("task %d consuming: line item: %v\n", task_num, item)
    }
    // each worker will drop out of their loop when channel is closed
}

queue 从切片更改为通道并提供项目,如下所示:

queue := make(chan string)

go func() {
    // loop through each line in the file and append it to the queue
    for scanner.scan() {
        queue <- scanner.text()
    }
    close(queue) // signal to workers that there is no more items
}()

然后只需更新您的工作调度程序代码即可添加渠道输入:

go func(i int) {
    consumer_task(i, queue) // add the queue parameter
    wg.Done()
}(i)

https://go.dev/play/p/AzHyztipUZI

好了,本文到此结束,带大家了解了《如何使该程序线程安全,通道是否是最佳实现,如果是,如何实现?》,希望本文对你有所帮助!关注golang学习网公众号,给大家分享更多Golang知识!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>