当前位置: 首页 > 面试题库 >

Golang,如何分享价值-消息还是互斥体?

荀金鹏
2023-03-14
问题内容

我已经完成了简单的基准测试,在传递消息和锁定共享值方面效率更高。

首先,请检查以下代码。

package main

import (
    "flag"
    "fmt"
    "math/rand"
    "runtime"
    "sync"
    "time"
)

type Request struct {
    Id      int
    ResChan chan Response
}

type Response struct {
    Id    int
    Value int
}

func main() {
    procNum := flag.Int("proc", 1, "Number of processes to use")
    clientNum := flag.Int("client", 1, "Number of clients")
    mode := flag.String("mode", "message", "message or mutex")
    flag.Parse()

    if *procNum > runtime.NumCPU() {
        *procNum = runtime.NumCPU()
    }

    fmt.Println("proc:", *procNum)
    fmt.Println("client:", *clientNum)
    fmt.Println("mode:", *mode)

    runtime.GOMAXPROCS(*procNum)

    rand.Seed(time.Now().UnixNano())
    var wg sync.WaitGroup

    sharedValue := 0

    start := time.Now()

    if *mode == "message" {
        reqChan := make(chan Request) // increasing channel size does not change the result
        go func() {
            for {
                req := <-reqChan
                sharedValue++
                req.ResChan <- Response{Id: req.Id, Value: sharedValue}
            }
        }()

        for i := 0; i < *clientNum; i++ {
            wg.Add(1)
            go func(index int) {
                defer wg.Done()
                c := make(chan Response)
                defer close(c)
                id := rand.Int()
                reqChan <- Request{Id: id, ResChan: c}
                <-c
            }(i)
        }
    } else if *mode == "mutex" {
        mutex := &sync.Mutex{}

        for i := 0; i < *clientNum; i++ {
            wg.Add(1)
            go func(index int) {
                defer wg.Done()
                mutex.Lock()
                sharedValue++
                mutex.Unlock()
            }(i)
        }
    }

    wg.Wait()
    elapsed := time.Since(start)

    fmt.Println("Elapsed:", elapsed, "value:", sharedValue)
}

您已经注意到,程序相对简单。在 消息模式下 ,它通过消息传递来增加sharedValue。在 互斥锁模式下 ,它通过锁定来增加
sharedValue

我尝试只将一个频道用于 消息模式 并放弃了。我认为这不可能,不是吗?

我的计算机有2个Xeon CPU,每个都有6个内核。由于超线程,逻辑上有24个内核可用。它的内存大小是12G。

如果我用任意数量的标志运行程序,则 互斥锁模式 总是至少快2倍(通常是3倍)。

好的,我可以理解,管理渠道需要一定的成本。然后,如果仅考虑性能,是否有任何理由使用通道而不是互斥锁?另外,巨大的消息量可以忽略消息传递成本吗?


问题答案:

如果仅考虑性能,是否有任何理由使用通道而不是互斥锁?

并不是的。维基页面“ 使用一个sync.Mutex或一个频道? ”说使用最富表现力和/或最简单的那个。
有一个用于Mutex的通道示例,但已注释如下:

尽管通道为受保护的数据提供了很好的解决方案,但是对于一个作者和许多读者来说,它的效率较低。

该线程添加:

如果您要共享数据,并且从不阻塞锁定部分,请使用互斥锁。
在非阻塞情况下,互斥对象确实很便宜

如果您有一些共享服务执行某些复杂或较长的工作,并且必须对其进行序列化,请考虑为其提供一个自己的goroutine,该例程可接收来自通道的html" target="_blank">请求并在完成后将回复发送回去。通常,您发送struct带有输入参数的a和用于回复的通道对象。
这很像RPC。

通道用于通信 ,而不是锁定。
如果仅出于锁定目的而通过通道发送无意义的数据,则可能会使事情复杂化。



 类似资料:
  • 问题内容: 阅读有关锁定PHP的一些文章。 它们主要都直接指向http://php.net/manual/en/function.flock.php。 本页讨论如何在硬盘上打开文件! 真的是这样吗?我的意思是,这使锁定变得非常昂贵-这意味着每次要锁定时,我都必须访问硬盘)= 能再给我一个令人愉快的消息安慰我吗? 编辑: 由于我已经收到了一些答复,我想问这个。 我的脚本只能由一个或多个线程运行?因为

  • 互斥是多线程系统中用于控制访问的一个原对象(primitive object)。下面的例子给出了它最基本的用法: std::mutex m; int sh; //共享数据 // … m.lock(); // 对共享数据进行操作: sh += 1; m.unlock(); 在任何时刻,最多只能有一个线程执行到lock()和unlock()之间的区域(通常称为临界区)。当第一个线程正在临界区执行时

  • Go语言包中的 sync 包提供了两种锁类型:sync.Mutex 和 sync.RWMutex。 Mutex 是最简单的一种锁类型,同时也比较暴力,当一个 goroutine 获得了 Mutex 后,其他 goroutine 就只能乖乖等到这个 goroutine 释放该 Mutex。 RWMutex 相对友好些,是经典的单写多读模型。在读锁占用的情况下,会阻止写,但不阻止读,也就是多个 gor

  • 上面的例子中,我们看过了如何在多个协程之间原子地访问计数器,对于更复杂的例子,我们可以使用Mutex来在多个协程之间安全地访问数据。 package main import ( "fmt" "math/rand" "runtime" "sync" "sync/atomic" "time" ) func main() { // 这个例子的状态就

  • 线程使用互斥量保护共享资源 线程使用互斥量保护共享资源 源码/* * Copyright (c) 2006-2018, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2018-08-24 yangjie the first versi

  • 互斥量接口 结构体 struct   rt_mutex   互斥量控制块 更多...   类型定义 typedef struct rt_mutex *  rt_mutex_t   互斥量类型指针定义   函数 rt_err_t  rt_mutex_init (rt_mutex_t mutex, const char *name, rt_uint8_t flag)   初始化互斥量   rt_err