成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Go 利用上下文進行并發計算,你學會了嗎?

開發
在測試中,我們期望 ??filterAll?? 會失敗,因為我們設置的超時時間只有一納秒。因此,上下文應該因為超過截止時間而發生錯誤。如果在啟動 Goroutine 進行下載內容過濾時不檢查 ??context.Err()??,我們將永遠不會處理此類錯誤。

在Go編程中,上下文(context)是一個非常重要的概念,它包含了與請求相關的信息,如截止日期和取消信息,以及在請求處理管道中傳遞的其他數據。在并發編程中,特別是在處理請求時,正確處理上下文可以確保我們尊重和執行請求中設定的限制,如截止時間。

讓我們通過一些代碼示例來探討如何在并發計算中使用上下文,以及如何在處理請求時尊重上下文所設定的截止日期和取消要求。

// download 函數用于下載給定 URL 的內容。
func download(ctx context.Context, url string) (string, error) {...}

download 函數嘗試獲取給定 URL 的內容。然而,需要注意的是,每個 URL 的下載內容可能不同,因此下載所需的時間也可能不同。如果在截止日期之前未能完成 URL 的下載,該函數將返回一個錯誤(截止日期錯誤)。

現在,假設我們需要下載許多 URL,并且我們只有有限的時間來完成這些下載。我們可以使用 errgroup 來并發地進行下載,如果超過截止時間,我們將取消所有并發操作。

// downloadAll 函數并發地下載給定 URL 的內容。
func downloadAll(ctx context.Context, urls []string) ([]string, error) {
  results := make([]string, len(urls))

  g, ctx := errgroup.WithContext(ctx)
  for i := range len(urls) {
    g.Go(func() error {
      content, err := download(ctx, urls[i])
      if err != nil {
        return err
      }

      results[i] = content
      return nil
    })
  }

  if err := g.Wait(); err != nil {
    return nil, err
  }

  return results, nil
}

在這個示例中,downloadAll 函數同時下載每個給定的 URL,并將相同的上下文傳遞給 download 函數。如果下載任何一個 URL 所需的時間超過了設定的截止時間,download 函數將失敗,從而導致整個并發流程也失敗,downloadAll 將返回一個截止日期錯誤。

除了下載這些 URL,我們還需要處理下載的內容。例如,我們可能要對每個 URL 的內容應用某個過濾器(謂詞)。

// filter 函數檢查給定內容是否符合給定的謂詞。
func filter(content string, pred func(string) bool) bool {
  return pred(content)
}

請注意,過濾器既不需要上下文,也不進行任何跨邊界調用。過濾器函數不關心上游處理的截止日期。

使用 filter 函數,我們可以定義一個過濾所有內容的函數。

// filterAll 函數同時過濾所有給定的內容。
func filterAll(contents []string, pred func(string) bool) []string {
  type Result struct {
    content string
    ok      bool
  }

  results := make([]Result, len(contents))

  g := errgroup.Group{}
  for i, content := range contents {
    g.Go(func() error {
      ok := filter(contents[i], pred)
      results[i] = Result{content: content, ok: ok}

      return nil
    })
  }

  g.Wait()

  var filtered []string
  for _, r := range results {
    if r.ok {
      filtered = append(filtered, r.content)
    }
  }

  return filtered
}

filterAll 函數調用 filter 函數來應用謂詞到每個內容上,但謂詞的應用可能會花費一些時間,可能超過上下文設置的截止時間。由于 filter 函數不使用上下文,因此它不會因為截止日期錯誤而失敗。

我們需要重新定義 filterAll,使其使用上下文并檢查其中的錯誤,而不管 filter 函數是否使用了上下文。

// filterAll 函數同時過濾所有內容,并檢查上下文中的錯誤。
func filterAll(ctx context.Context, contents []string, pred func(string) bool) ([]string, error) {
  type Result struct {
    content string
    ok      bool
  }

  results := make([]Result, len(contents))

  g, ctx := errgroup.WithContext(ctx)
  for i, content := range contents {
    g.Go(func() error {
      if err := ctx.Err(); err != nil {
        return err
      }

      ok := filter(contents[i], pred)
      results[i] = Result{content: content, ok: ok}

      return nil
    })
  }

  if err := g.Wait(); err != nil {
    return nil, err
  }

  var filtered []string
  for _, r := range results {
    if r.ok {
      filtered = append(filtered, r.content)
    }
  }

  return filtered, nil
}

我們的新實現 filterAll 函數會檢查上下文中的任何錯誤,即使上下文并未直接傳遞給下游函數(在本例中為 filter)。如果發生了與上下文相關的截止日期(或任何其他錯誤),整個過濾過程就會失敗。

現在,讓我們完成對所有內容的處理。

// processURLs 函數下載每個 URL 的內容并對其進行過濾。
//
// 處理必須在上下文截止日期內完成。
func processURLs(ctx context.Context, urls []string) ([]string, error) {
  contents, err := downloadAll(ctx, urls)
  if err != nil {
    return nil, err
  }

  filtered, err := filterAll(ctx, contents, somePredicate)

  return filtered, err
}

如果任何一個下載操作花費的時間過長,那么在嘗試獲取內容時就會發生截止日期錯誤,因為上下文被直接用于 API 調用。因此,downloadAll 函數也會失敗,進而導致 processURLs 失敗。

如果所有的 URL 在截止日期內都被正確下載,我們將繼

續對它們進行過濾。在對每個下載內容進行過濾時,不使用上下文,但 filterAll 函數明確地檢查上下文中的錯誤,如果發生了與上下文相關的截止日期(或任何其他錯誤),整個過濾過程就會失敗。

有時候,僅僅使用 errgroup.WithContext 是不足以檢測到上下文中的截止日期或其他問題的,特別是當上下文未直接使用時。因此,我們應該定期檢查是否仍在時間限制內,否則就會失敗。

最后,我們可以通過編寫 filterAll 的測試來確保我們正確地處理了類似的情況,以確保我們尊重與上下文相關的任何錯誤。

func TestContextError(t *testing.T) {
  ctx, done := context.WithTimeout(context.Background(), time.Nanosecond)
  defer done()

  // 生成我們想要應用過濾器的一些數據。
  var contents []string = testingContent()

  _, err := filterAll(ctx, contents, thePredicate)
  if err == nil {
    t.Errorf("filterAll() = %v, want error", err)
  }
}

請注意,在測試中,我們期望 filterAll 會失敗,因為我們設置的超時時間只有一納秒。因此,上下文應該因為超過截止時間而發生錯誤。如果在啟動 Goroutine 進行下載內容過濾時不檢查 context.Err(),我們將永遠不會處理此類錯誤。

責任編輯:武曉燕 來源: 愛發白日夢的后端
相關推薦

2025-02-26 00:16:56

RAGAI服務

2024-02-21 19:02:05

Go模板化方式

2017-05-11 14:00:02

Flask請求上下文應用上下文

2023-01-29 08:08:34

并發庫conc通用庫

2022-01-17 07:50:37

Go代碼規范

2023-04-26 00:41:36

A/B測試郵件數量

2022-08-29 08:05:44

Go類型JSON

2023-08-01 12:51:18

WebGPT機器學習模型

2024-01-02 12:05:26

Java并發編程

2025-06-20 09:57:42

2021-07-26 07:47:36

Cpu上下文進程

2023-06-26 08:02:34

JSR重排序volatile

2024-03-18 08:06:59

JavaGo開發

2024-01-19 08:25:38

死鎖Java通信

2024-02-04 00:00:00

Effect數據組件

2023-07-26 13:11:21

ChatGPT平臺工具

2023-01-10 08:43:15

定義DDD架構

2024-01-26 06:05:16

KuberneteseBPF網絡

2024-05-30 09:43:00

2024-03-06 08:28:16

設計模式Java
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品一区二区久久久久久久网精 | 国产一区二区精品在线观看 | 精品欧美一区二区精品久久久 | 国产精品久久av | 国产成人免费视频网站高清观看视频 | 日韩中文一区 | 国产精品久久av | 伊人免费在线观看 | 国产精品99久久久久久动医院 | 波多野结衣中文视频 | 欧美日韩一区二区三区不卡视频 | caoporn免费在线视频 | 免费成人高清 | 亚洲第一区国产精品 | 天天久久 | 国产视频久 | 四虎成人av| 福利视频网址 | 国产永久免费 | 久久91精品 | 夜夜爽99久久国产综合精品女不卡 | 免费性视频 | 中文在线亚洲 | 天天干狠狠干 | 日韩一区二区三区av | 欧美日韩综合一区 | 欧美 中文字幕 | 精品日本久久久久久久久久 | 国产乱码精品一区二区三区中文 | 久久精品91久久久久久再现 | 日韩欧美三区 | 波多野结衣一区二区三区在线观看 | 日本三级电影免费观看 | 亚洲精品www| 久久精品国产一区二区电影 | 日韩精品成人av | 免费在线观看一级毛片 | 久久久不卡网国产精品一区 | 国产一区二区观看 | 男人天堂网站 | 99亚洲|