Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 戈朗双向渠道沟通_Multithreading_Go_Concurrency_Locking - Fatal编程技术网

Multithreading 戈朗双向渠道沟通

Multithreading 戈朗双向渠道沟通,multithreading,go,concurrency,locking,Multithreading,Go,Concurrency,Locking,我有几个函数,我希望它们能够原子化执行,因为它们处理敏感的数据结构。假设以下场景: 有两个函数:lock(sth)和unlock(sth),可由goroutine随时调用,以在全局数组中锁定或解锁sth。我在考虑使用一个命令通道,这样goroutines就可以将lock和unlock命令发送到通道中,在通道的接收端,某种处理程序通过从通道中获取命令来依次处理lock,unlock请求。这很好,但是如果处理程序想要将结果发送回请求者呢?是否可以使用golang通道进行此操作?我知道可以使用某种锁机

我有几个函数,我希望它们能够原子化执行,因为它们处理敏感的数据结构。假设以下场景: 有两个函数:
lock(sth)
unlock(sth)
,可由goroutine随时调用,以在全局数组中锁定或解锁
sth
。我在考虑使用一个命令通道,这样goroutines就可以将
lock
unlock
命令发送到通道中,在通道的接收端,某种
处理程序通过从通道中获取命令来依次处理
lock
unlock
请求。这很好,但是如果
处理程序
想要将结果发送回请求者呢?是否可以使用golang通道进行此操作?我知道可以使用某种锁机制,比如互斥锁,但我想知道在这种情况下是否可以使用通道?我在某处看到,建议使用channel而不是goland低级锁结构

一句话:

在容量为1的通道中,我希望接收方能够回复发送消息的goroutine

或相当于:


goroutine向通道发送某物;消息被另一个goroutine接收并进行处理,从而产生某种结果;发送方是如何知道结果的?

sync
包包含一个互斥锁,
sync.Mutex
,可以通过线程安全的方式从任何goroutine锁定和解锁。与其使用通道发送命令来锁定某些内容,不如直接使用发送方的互斥锁

mutex := new(sync.Mutex)
sensitiveData := make([]string, 0)
// when someone wants to operate on a sensitiveData,
// ...
mutex.Lock()
operate(sensitiveData)
mutex.Unlock()
当你说发送者是如何意识到结果的时候,我想你是在说处理程序是如何接收结果的——这将是一个
chan
。您可以通过通道发送数据

或者,如果您只是想知道,一个信号量,
sync.WaitGroup
可以完成这项工作。此结构可以
Add()
ed to,然后发送方可以
wg.Wait()
,直到处理程序调用
wg.Done()
,这将向发送方(正在等待的)指示处理程序已完成这样或那样的操作


如果您的问题是关于是否使用锁或通道,则有一个简短的答案:

一个常见的新手错误是过度使用频道和goroutines仅仅因为它是可能的,和/或因为它很有趣。如果sync.Mutex最适合您的问题,请不要害怕使用它。Go是务实的,它允许您使用能够最好地解决问题的工具,而不是强迫您使用一种代码风格

但作为一般指南:

通道:传递数据所有权、分配工作单元、交流异步结果
互斥:缓存,状态


如果您绝对不想避免任何事情,但
chan
s:),请尝试从一开始就不要更改敏感数组。相反,使用通道将数据发送到不同的goroutine,在每个步骤处理数据,然后将处理后的数据导入最终类型的goroutine。也就是说,完全避免使用数组,并将数据存储在
chan
s中

正如格言所说

不要通过共享内存进行交流;相反,通过交流来共享内存


如果您想防止竞争条件,那么
sync
原语应该可以正常工作,如@Nevermore的回答中所述。它使代码更具可读性,更易于推理

但是,如果希望频道为您执行同步,您可以尝试以下操作:

// A global, shared channel used as a lock. Capacity of 1 allows for only
// one thread to access the protected resource at a time.
var lock = make(chan struct{}, 1)


// Operate performs the access/modification on the protected resource.
func Operate(f func() error) error {
    lock <- struct{}{}
    defer func() { <- lock }()
    return f()
}
工作示例:

或者您可以完全绕过
操作
,直接使用
锁定
,以提高可读性:

go func(j int) {
    defer wg.Done()

    lock <- struct{}{}
    defer func() { <- lock }()

    arr[j] *= 2
}(i)
go func(j int){
推迟工作组完成()

lock其他问题已经很好地涵盖了锁定,但我想解决问题的另一部分,即使用通道将响应发送回调用方。在发送响应通道和请求时,有一种常见的模式。例如,您可以通过通道向处理程序发送命令;这些命令将是
struct
具有特定于实现的详细信息,该结构将包括一个用于将结果发送回的通道,输入到结果类型。发送的每个命令将包括一个新通道,处理程序将使用该通道发送回响应,然后关闭。如图所示:

type Command struct {
    // command parameters etc
    Results chan Result
}

type Result struct {
    // Whatever a result is in this case
}

var workQueue = make(chan Command)

// Example for executing synchronously
func Example(param1 string, param2 int) Result {
    workQueue <- Command{
        Param1: param1,
        Param2: param2,
        Results: make(chan Result),
    }
    return <- Results
type命令结构{
//命令参数等
结果
}
类型结果结构{
//不管这个案子的结果如何
}
var workQueue=make(chan命令)
//同步执行的示例
func示例(param1字符串,param2 int)结果{

工作队列非常感谢您的精确回答!:-)这非常有帮助,我承认最简单的方法是使用
互斥体。但是,根据我有限的经验,如果可能的话,使用消息传递处理并发问题要比使用共享内存解决方案容易得多。我想知道是否有可能解决这个问题如果不使用信号量或互斥量,只使用golang通道,现在我发现使用
互斥量是完全可以的。嗨@shidsun,我不确定我是否理解你的问题:),也许一些psuedo代码会有帮助?无论如何,我的建议是完全避免数组(如果你只想使用通道)并尝试将数据存储在
chan
s中。
type Command struct {
    // command parameters etc
    Results chan Result
}

type Result struct {
    // Whatever a result is in this case
}

var workQueue = make(chan Command)

// Example for executing synchronously
func Example(param1 string, param2 int) Result {
    workQueue <- Command{
        Param1: param1,
        Param2: param2,
        Results: make(chan Result),
    }
    return <- Results