如果函数在 Golang 中使用 mutex.lock() 被锁定,如何发送响应?

我有这个功能。


func (s *eS) Post(param *errorlogs.Q) (*errorlogs.Error, *errors.RestErr) {

    //sub := q.Get("sub")

    s.mu.Lock()

    utime := int32(time.Now().Unix())


    // Open our jsonFile

    jsonFile, errFile := getlist(param.Id)

    // if we os.Open returns an error then handle it

    if errFile != nil {

        return nil, errFile

    }


    jsonFile, err := os.Open(dir + "/File.json")

    // if we os.Open returns an error then handle it

    if err != nil {

        return nil, errors.NewNotFoundError("Bad File request")

    }

    // read our opened jsonFile as a byte array.

    byteValue, _ := ioutil.ReadAll(jsonFile)

    // we initialize our  model

    var errorFile errorlogs.Error_File

    // we unmarshal our byteArray which contains our

    // jsonFile's content into '' which we defined above

    json.Unmarshal(byteValue, &errorFile)

    // defer the closing of our jsonFile so that we can parse it later on

    defer jsonFile.Close()

    // An object to copy the required data from the response

    var id int32

    if len(errorFile.Error) == 0 {

        id = 0

    } else {

        id = errorFile.Error[len(errorFile.Error)-1].ID

    }


    newValue := &errorlogs.Error{

        ID:         id + 1,

        Utime:      utime,

    

    }


    errorFile.Error = append(errorFile.Error, *newValue)

    file, err := json.Marshal(errorFile)

    if err != nil {

        return nil, errors.NewInternalServerError("Unable to json marshal file")

    }

    err = ioutil.WriteFile(dir+"/File.json", file, 0644)

    if err != nil {

        return nil, errors.NewInternalServerError("Unable to write file")

    }

    s.mu.Unlock()


    return newValue, nil


}

在这里,我从并发请求中锁定此函数,如果某个客户端已经写入文件,则不会让另一个客户端同时写入该文件。但现在我感到困惑,这个互斥体是什么。Lock() 在锁定时对所有其他请求执行操作?它是否让其他客户端等待?还是只是忽略所有其他客户端?我们有什么办法用某种回应发回客户端吗?或者让另一个客户端等待,然后允许他们访问此功能?


海绵宝宝撒
浏览 100回答 1
1回答

人到中年有点甜

当互斥体被锁定时,对互斥锁()的所有其他调用都将被阻止,直到首先调用互斥锁()为止。因此,当处理程序正在运行(并持有互斥锁)时,所有其他请求将在调用时被阻止。Lock()注意:如果您的处理程序由于您提前返回(使用语句)而无法正常完成,或者它崩溃了,您的互斥锁将保持锁定状态,因此所有进一步的请求都将被阻止。return一个好的做法是在互斥体被锁定后立即使用&nbsp;defer&nbsp;来解锁它:s.mu.Lock() defer&nbsp;s.mu.Unlock()这确保了无论您的函数如何结束(可能正常结束,返回或恐慌),都将被调用。Unlock()尝试尽可能少地保持锁定,以最大程度地减少其他请求的阻塞时间。虽然在进入处理程序时正确锁定并在返回之前仅解锁可能很方便,但如果在处理程序的“生存期”内不使用受保护的资源,则仅在使用共享资源时才锁定和解锁。例如,如果要保护对文件的并发访问,请锁定互斥锁,读/写文件,并在完成后立即解锁互斥锁。如何处理读取数据以及如何组装和发送响应不应阻止其他请求。当然,在使用解锁时,它可能不会像它应该的那样早运行(当您完成共享资源时)。因此,在某些情况下,可以使用 不使用 ,或者访问共享资源的代码可能会被移动到命名或未命名(匿名)函数,以便仍然能够使用 。deferdeferdefer同步。互斥体不支持“扫视”状态,也不支持“尝试锁定”操作。这意味着使用时,您无法向客户端发出它必须等待的信号,因为处理请求正在等待另一个请求完成。如果您需要此类功能,则可以使用通道。容量为 1 的缓冲通道可以实现此功能:“锁定”操作在通道上发送值,“解锁”操作从通道接收值。目前为止,一切都好。“try-lock”操作可以是“有条件的”发送操作:使用带有事例的&nbsp;select&nbsp;语句,您可以检测到您现在无法锁定,因为它已被锁定,您可以执行其他操作或同时执行其他操作,并在以后重试锁定。sync.Mutexdefault下面是一个示例:它可能看起来像这样:var lock = make(chan struct{}, 1)func handler(w http.ResponseWriter, r *http.Request) {&nbsp; &nbsp; // Try locking:&nbsp; &nbsp; select {&nbsp; &nbsp; case lock <- struct{}{}:&nbsp; &nbsp; &nbsp; &nbsp; // Success: proceed&nbsp; &nbsp; &nbsp; &nbsp; defer func() { <-lock }() // Unlock deferred&nbsp; &nbsp; default:&nbsp; &nbsp; &nbsp; &nbsp; // Another handler would block us, send back an "error"&nbsp; &nbsp; &nbsp; &nbsp; http.Error(w, "Try again later", http.StatusTooManyRequests)&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; }&nbsp; &nbsp; time.Sleep(time.Second * 2) // Simulate long computation&nbsp; &nbsp; io.WriteString(w, "Done")}func main() {&nbsp; &nbsp; http.HandleFunc("/", handler)&nbsp; &nbsp; log.Fatal(http.ListenAndServe(":8080", nil))}上面的简单示例如果另一个请求持有锁定,则会立即返回错误。你可以选择在这里做不同的事情:你可以把它放在一个循环中,在放弃并返回错误之前重试几次(在迭代之间稍微睡觉)。您可以在尝试锁定时使用超时,并且只有在一段时间内无法获得锁定时才接受“失败”(请参阅时间。After() 和上下文。WithTimeout())。当然,如果我们使用某种超时,则必须删除该案例(如果其他案例都不能立即进行,则立即选择该案例)。defaultdefault当我们处于它(超时)时,由于我们已经在使用 ,因此我们可以合并监视请求的上下文是一个好处:如果它被取消,我们应该提前终止并返回。为此,我们可以通过添加从上下文的 done 通道接收的案例来执行此操作,例如 。selectcase <-r.Context().Done():下面是一个示例,如何简单地使用:selectvar lock = make(chan struct{}, 1)func handler(w http.ResponseWriter, r *http.Request) {&nbsp; &nbsp; // Wait 1 sec at most:&nbsp; &nbsp; ctx, cancel := context.WithTimeout(r.Context(), time.Second)&nbsp;&nbsp; &nbsp; defer cancel()&nbsp; &nbsp; // Try locking:&nbsp; &nbsp; select {&nbsp; &nbsp; case lock <- struct{}{}:&nbsp; &nbsp; &nbsp; &nbsp; // Success: proceed&nbsp; &nbsp; &nbsp; &nbsp; defer func() { <-lock }() // Unlock deferred&nbsp; &nbsp; case <-ctx.Done():&nbsp; &nbsp; &nbsp; &nbsp; // Timeout or context cancelled&nbsp; &nbsp; &nbsp; &nbsp; http.Error(w, "Try again later", http.StatusTooManyRequests)&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; }&nbsp; &nbsp; time.Sleep(time.Second * 2) // Simulate long computation&nbsp; &nbsp; io.WriteString(w, "Done")}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go