有没有办法让多个函数在 Go 后端同时运行?

问题描述 投票:0回答:1

假设您想在数据库中引入一个条目,比如说,由于缺乏更好的例子,您想在书籍和作者数据库中引入一个书籍条目。所以,我对于这个插入的心理模型会是这样的。

  1. 我首先使用这段代码将结构体的书籍相关字段插入到数据库中:
query := `
        INSERT INTO books(book_id,title,publisher,year,page_count,genres)
        VALUES($1,$2,$3,$4,$5,$6)
        RETURNING id,book_id,title,publisher,year,page_count,genres
    `

    args := []interface{}{
        entry.Book.Hash,
        entry.Book.Title,
        entry.Book.Publisher,
        entry.Book.Year,
        entry.Book.PageCount,
        pq.Array(entry.Book.Genres)}

    err := tx.QueryRowContext(ctx, query, args...).Scan(
        &read.Book.ID,
        &read.Book.Hash,
        &read.Book.Title,
        &read.Book.Publisher,
        &read.Book.Year,
        &read.Book.PageCount,
        pq.Array(&read.Book.Genres))

    if err != nil {
        return err
    }
  1. 然后我将作者姓名插入到单独的作者表中,检查作者是否已经存在,然后代码应该将 books_authored 计数器加一。该操作的代码如下:
query = `
        WITH filter1 AS(
            SELECT
            UNNEST($1::TEXT[]) AS name,
            UNNEST($2::TEXT[]) AS author_id,
            1 as books_authored
        ), finished AS(
            INSERT INTO authors(name,author_id,books_authored)
            SELECT name, author_id, books_authored FROM filter1
            ON CONFLICT (author_id) DO UPDATE
            SET books_authored = authors.books_authored + 1
            RETURNING id, name, author_id, books_authored
        )
        SELECT array_agg(id), array_agg(name), array_agg(author_id), array_agg(books_authored) FROM finished
    `

    args = []interface{}{pq.Array(entry.Authors.List), pq.Array(entry.Authors.Hash)}
    err = tx.QueryRowContext(ctx, query, args...).Scan(
        pq.Array(&read.List.ID),
        pq.Array(&read.List.Name),
        pq.Array(&read.List.Identifier),
        pq.Array(&read.List.Books_authored),
    )

    if err != nil {
        return err
    }
  1. 然后,我在书籍/作者表中创建一个条目,该表仅将书籍 ID 与不同的作者 ID 相关联。使用以下代码。
    query = `
    WITH cte AS (
        SELECT book_id, author_id FROM
        UNNEST($1::TEXT[]) AS book_id,
        UNNEST($2::TEXT[]) AS author_id 
  ), finished AS (
    INSERT INTO book_author_link(book_id, author_id)
    SELECT book_id, author_id FROM cte
    ON CONFLICT (book_id, author_id) DO NOTHING
    RETURNING book_id, author_id
  )
  SELECT array_agg(book_id), array_agg(author_id) FROM finished
  
    `

    args = []interface{}{pq.Array([]string{entry.Book.Hash}), pq.Array(entry.Authors.Hash)}

    return tx.QueryRowContext(ctx, query, args...).Scan(
        pq.Array(entry.Authors.List),
        pq.Array(entry.Authors.Hash),
    )

一切都是使用 SQL 事务完成的,以便仅在完成前面的所有步骤后才能创建条目。所以我的问题是我是否可以同时执行第一步和第二步,检查两个 goroutine 是否成功完成并继续第三步。

有关更多信息,我确实尝试使用

sync/mutex
包但无济于事,我不知道使用 http 包锁定所有 goroutine 是否会锁定在后台运行的所有其他进程。但是当我使用
sync/waitGroup
时。

go concurrency
1个回答
0
投票

我对 GoLang 也很陌生,但你可以使用通道来实现这一点。一个简约的例子: 创建两个 bool 类型的通道并为每个函数分配一个通道。每个 goroutine 将成功结果(真/假)放入其通道中。你的第三个 goroutine 可以在后台永久运行并监听两个通道。如果这两个条目都是真的,那就让你的魔法发生吧:)。第三个 goroutine 可能如下所示:

func Success(ch1, ch2 chan bool) {
    for val1ok := range ch1 {
        for val2ok := range ch2 {
            if val1ok && val2ok {
                fmt.Println("All Okay")
                break
            }
            fmt.Println("Not Okay")
        }
    }
}

对于你来说,当然会有更多的逻辑。例如:结构体等等以及这本书与作者匹配吗?可能是一个想法,为两个 goroutine 提供类似于每对的主键的东西,将所有内容缓存在第三个 goroutine 中并将其分配回一起。如果比赛已处理或超过特定时间,请不要忘记删除。

© www.soinside.com 2019 - 2024. All rights reserved.