【问题标题】:Race condition against Google Photos API针对 Google Photos API 的竞争条件
【发布时间】:2020-11-26 10:35:46
【问题描述】:

我正在开发 this CLI 以将图像上传到 Google 相册。 CLI 创建了几个 go 例程来并行上传文件1。上传后,相同的例程会将其添加到Album。如果在2 之前不存在这些相册,则会创建这些相册。

由于并发性以及 Google Photos API 允许创建两个具有相同名称的Albums,我希望避免出现重复的相册名称。

GetOrCreateAlbumByName() 3 并不能确保 Album 是唯一的。它基本上询问是否存在同名的专辑,如果不存在,它将创建一个新专辑。但是这个函数可以并行调用,所以可以创建两个同名的Album。除了实现互斥之外,我还在观察重复项。

您建议如何处理?

  1. 创建一个处理相册创建的 Worker(如微服务)。在创建相册之前,每个 goroutine 都将被阻止。它将删除Album 创建部分的并发性。
  2. 维护一个相册缓存并使用它来检查相册是否已经创建。在这种情况下,竞争条件也可能发生,但概率较小。
  3. 同时使用 1 和 2。
  4. 其他,请说明。

我对 1、2 和 3 有疑虑...这就是为什么我想知道您将如何处理。

提前致谢

【问题讨论】:

  • 我假设您使用Client.GetOrCreateAlbum(),如果相册已经存在,它不会创建副本。有什么问题?
  • 请提供更多详细信息,这样我们就不必检查您的整个应用程序。 minimal reproducible example 会很好。
  • 我已经编辑了问题以包含我认为可以更好地解释问题的代码部分。
  • Client.GetOrCreateAlbumByName() 使用互斥体,因此并发调用不会创建重复项,但是您的代码(可能)创建和使用多个客户端,每个客户端都有自己的互斥体,因此它们仍然可能创建重复项。使用单个Client。或者,如果您必须使用多个客户端,请使用单个互斥锁或其他方式来序列化所有 GetOrCreateAlbumByName() 调用。
  • 这样就解决了?

标签: go concurrency goroutine


【解决方案1】:

您使用Client.GetOrCreateAlbumByName() 获取或创建相册。这种方法对于并发使用是安全的,它在内部使用互斥锁来序列化调用,从而确保不会创建重复。

但是,您正在创建和使用多个客户端 here,这意味着对所有客户端的并发调用不会序列化,只会对单个客户端进行并发调用。

所以解决方案要么使用单个客户端,然后所有调用都将被序列化,或者如果这不可能,您必须序列化对所有客户端的调用,例如使用单个互斥锁或其他方式。

如何使用互斥锁序列化对所有客户端的调用的示例:

var mu sync.Mutex

func GetOrCreateAlbumByName(c *gphotos.Client, name string) (*photoslibrary.Album, error) {
    mu.Lock()
    defer mu.Unlock()
    return c.GetOrCreateAlbumByName(name)
}

无论您在哪里使用client.GetOrCreateAlbumByName(name),都将其替换为调用:

GetOrCreateAlbumByName(client, name)

【讨论】:

    猜你喜欢
    • 2022-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-18
    • 2022-01-23
    • 2018-10-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多