Go 中有效并发的模式

在这里插入图片描述

设计高效可靠的并发系统

在现代软件开发领域中,利用并发的能力已经变得至关重要。随着应用程序的复杂性增加和数据处理需求的增长,编写既高效又可靠的并发代码成为了一个重要的关注点。为了解决这个挑战,开发者们已经制定了一些模式和最佳实践,以实现有效地设计和管理并发系统。在本文中,我们将深入探讨 Go 中有效并发的五个基本模式:理解并行性和并发性的区别、任务分解的概念、工作池的实用性、取消和上下文,以及测试并发代码。

并行性与并发性

在我们深入了解并发模式的复杂性之前,理解并行性和并发性之间的基本区别是至关重要的。

并行性

并行性涉及同时执行多个任务,通常主要目的是通过利用多个处理器核心的能力来提高性能。在真正的并行情境中,任务会并发执行,无需它们之间的同步或协调。并行性通常用于计算密集型任务,如科学模拟、渲染和数据处理。

并发性

另一方面,并发性是一个更广泛的概念。它指的是系统同时管理和执行多个在时间上重叠的任务的能力。这些任务可能不一定并行运行,而是以交错的方式运行。并发旨在有效地利用资源,提高响应性,并在无法实现真正的并行性的情况下并发处理任务。

有了对并行性和并发性的基础理解,让我们深入探讨如何在 Go 中实现有效并发的实际模式。

任务分解

任务分解是设计并发系统的基本模式。这种模式涉及将一个复杂任务分解为更小、更易管理的子任务,这些子任务可以并发执行。这种方法不仅有助于充分利用您的硬件潜力,还增强了代码的模块化和可维护性。

需要任务分解

想象一下,您需要处理一个大型数据集的场景。如果没有任务分解,您可能选择按顺序处理每个项目。然而,尤其是在现代多核处理器的背景下,这种方法可能会非常慢,因为处理器资源没有得到充分利用。

使用任务分解进行并行化

任务分解允许您将数据集划分为更小的块并并发处理它们。这种策略使您能够实现并行性并充分利用硬件资源。让我们用一个简单的 Go 示例来说明这个概念。

package main

import (
	"fmt"
	"sync"
)

func processItem(item int, wg *sync.WaitGroup, results chan int) {
	defer wg.Done()

	// Simulate item processing
	// ...

	// Send the result to the channel
	results <- item * 2
}

func main() {
	numItems := 100
	numWorkers := 4

	// Create a wait group to synchronize workers
	var wg sync.WaitGroup

	// Create a channel to collect results
	results := make(chan int, numItems)

	// Launch worker goroutines
	for i := 0; i < numWorkers; i++ {
		wg.Add(1)
		go processItem(i, &wg, results)
	}

	// Close the results channel when all workers are done
	go func() {
		wg.Wait()
		close(results)
	}()

	// Collect and process results
	for result := range results {
		fmt.Printf("Processed result: %d\n", result)
	}
}

在这个 Go 示例中,我们利用 goroutines 和 channels 来实现任务分解。processItem 函数模拟了项的处理,每个项都被并发处理。通过将工作负载分解为更小、可并行化的子任务,我们有效地利用了并发的好处。

工作池

工作池是另一个非常重要的并发模式,特别是在处理需要并发执行的大量任务时。与为每个任务创建一个新的 goroutine 不同,工作池维护了一定数量的工作 goroutines,这些 goroutines 从队列中处理任务。这种模式有助于管理资源消耗并防止系统过载。

无限并发的挑战

如果没有工作池,您可能会尝试为每个任务创建一个新的 goroutine,尤其是在处理大量任务时。然而,这种方法可能导致资源耗尽、上下文切换开销增加和潜在的不稳定性。

在 Go 中实现工作池

让我们通过一个简化的 Go 示例来说明工作池的概念。

package main

import (
	"fmt"
	"sync"
)

type Task struct {
	ID     int
	Result int
}

func worker(id int, tasks <-chan Task, results chan<- Task, wg *sync.WaitGroup) {
	defer wg.Done()

	for task := range tasks {
		// Simulate task processing
		// ...

		// Store the result in the task
		task.Result = task.ID * 2

		// Send the updated task to the results channel
		results <- task
	}
}

func main() {
	numTasks := 20
	numWorkers := 4

	// Create a wait group to synchronize workers
	var wg sync.WaitGroup

	// Create channels for tasks and results
	tasks := make(chan Task, numTasks)
	results := make(chan Task, numTasks)

	// Launch worker goroutines
	for i := 0; i < numWorkers; i++ {
		wg.Add(1)
		go worker(i, tasks, results, &wg)
	}

	// Generate tasks
	for i := 0; i < numTasks; i++ {
		tasks <- Task{ID: i}
	}

	// Close the tasks channel to signal that no more tasks will be added
	close(tasks)

	// Wait for all workers to finish
	wg.Wait()

	// Close the results channel
	close(results)

	// Collect and process results
	for result := range results {
		fmt.Printf("Processed result for task %d: %d\n", result.ID, result.Result)
	}
}

在这个 Go 示例中,我们使用 goroutines 和 channels 实现了一个工作池。工作 goroutines 并发地从 tasks 通道处理任务,并将结果发送回 results 通道。通过维护一定数量的工作 goroutines,我们确保只有有限数量的任务被并发执行,从而防止资源耗尽。

取消和上下文

取消和上下文管理是并发编程的关键方面。当处理并发任务时,有必要设置机制来取消正在进行的工作或管理任务执行的上下文。

Go 中的上下文和取消上下文

Go 提供了 context 包,该包允许您在 API 边界和进程之间传递截止日期、取消和其他请求范围的值。这个包特别适用于管理并发任务的生命周期。

让我们看一个使用 context 进行取消的示例:

package main

import (
	"context"
	"fmt"
	"sync"
	"time"
)

func worker(ctx context.Context, id int, wg *sync.WaitGroup) {
	defer wg.Done()

	select {
	case <-ctx.Done():
		fmt.Printf("Worker %d: Canceled\n", id)
		return
	case <-time.After(time.Second):
		fmt.Printf("Worker %d: Done\n", id)
	}
}

func main() {
	numWorkers := 4

	// Create a context with a cancellation function
	ctx, cancel := context.WithCancel(context.Background

())
	defer cancel() // Ensure cancellation when done

	// Create a wait group to synchronize workers
	var wg sync.WaitGroup

	// Launch worker goroutines
	for i := 0; i < numWorkers; i++ {
		wg.Add(1)
		go worker(ctx, i, &wg)
	}

	// Cancel the context after a brief delay
	go func() {
		time.Sleep(2 * time.Second)
		cancel()
	}()

	// Wait for all workers to finish
	wg.Wait()
}

在这个 Go 示例中,我们使用 context.WithCancel 创建了一个带有取消功能的上下文。我们启动了多个工作 goroutines,并且每个工作器通过 ctx.Done() 来检查取消。当上下文被取消时(在这种情况下,经过短暂的延迟),工作器会适当地响应并退出。

测试并发代码

测试并发代码带来了独特的挑战。确保您的并发代码正确且可靠是非常重要的,以避免竞态条件和其他与并发相关的问题。Go 提供了工具和技术来有效地测试并发代码。

在 Go 中测试并发代码

Go 的测试框架包括 testing 包,它允许您为并发代码编写单元测试。您可以使用 go test 命令并行运行这些测试,这有助于发现竞态条件和同步问题。

让我们看一个在 Go 中测试并发代码的示例:

package main

import (
	"sync"
	"testing"
)

func ParallelFunction() int {
	var wg sync.WaitGroup
	var result int
	numWorkers := 4

	wg.Add(numWorkers)
	for i := 0; i < numWorkers; i++ {
		go func(id int) {
			defer wg.Done()
			result += id
		}(i)
	}

	wg.Wait()
	return result
}

func TestParallelFunction(t *testing.T) {
	expected := 6 // Sum of integers from 0 to 3
	result := ParallelFunction()

	if result != expected {
		t.Errorf("Expected %d, but got %d", expected, result)
	}
}

在这个 Go 示例中,我们有一个名为 ParallelFunction 的函数,它通过启动多个 goroutines 执行并行计算。然后,我们有一个名为 TestParallelFunction 的单元测试,用于检查函数是否按预期行为。

要运行测试,请使用 go test 命令,该命令会自动检测并运行当前包中的测试。

go test

结论

并发是增强软件性能和响应性的有力工具。这不仅仅是关于同时运行任务,还关于以一种可管理、高效和可靠的方式这样做。理解并行性和并发性之间的区别是做出明智设计决策的基础。

任务分解使您能够将复杂任务分解为更小、可并行化的子任务,从而最大化资源利用和代码可维护性。工作池提供了一种结构化方法来高效管理并发任务,当处理大量任务负载时,可以防止资源过载和不稳定性。

取消和上下文管理对于优雅地处理并发任务至关重要,允许在需要时进行取消和清理。Go 的 context 包是实现这一点的强大工具。

测试并发代码对于确保实现的正确性至关重要。Go 的测试框架以及并行运行测试的能力有助于识别和减轻竞态条件和其他与并发相关的问题。

通过将这些模式纳入您的 Go 编程工具包中,您可以设计和实现充分利用现代计算资源能力的有效并发系统。有效的并发不仅仅是同时执行更多任务的问题,还需要精确控制,确保应用程序的稳定性和健壮性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/275905.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java freemarker 动态生成excel文件

好久木有更新啦 抓住2023的小尾巴 浅浅更新一下吧~ 最近做了一个动态生成excel的功能&#xff0c;这里记录下部分功能&#xff0c;主要用到的是freemarker框架&#xff0c;spring就有带&#xff0c;我起的demo载入了一下freemarker的jar包 一、创建模板 首先可以创建一个e…

百度每天20%新增代码由AI生成,Comate SaaS服务8000家客户 采纳率超40%

12月28日&#xff0c;由深度学习技术及应用国家工程研究中心主办的WAVE SUMMIT深度学习开发者大会2023在北京召开。百度首席技术官、深度学习技术及应用国家工程研究中心主任王海峰现场公布了飞桨文心五载十届最新生态成果&#xff0c;文心一言最新用户规模破1亿&#xff0c;截…

idea中切换JDK8、JDK11、JDK17

有时候&#xff0c;我们可能需要在不同的Java版本中去测试或者查看源码&#xff0c;idea可以让我们修改Java的版本。 前提&#xff1a;你必须下载安装好对应的Java版本&#xff0c;可参考文章【windows下切换JDK8、JDK11、JDK17】&#xff08;https://blog.csdn.net/xijinno1/a…

九九乘法表c 语言 用于打印九九乘法表

以下是一个简单的C语言程序&#xff0c;用于打印九九乘法表&#xff1a; #include <stdio.h>int main() {int i, j;for (i 1; i < 9; i) {for (j 1; j < i; j) {printf("%d*%d%-2d ", j, i, i*j);}printf("\n");}return 0; }解释&#xff1…

快速上手makefile自动化构建工具

makefile自动化构建工具 文章目录 makefile自动化构建工具 makefile背景 简单认识makefile 依赖关系与依赖方法 生成项目 清理项目 ACM时间 语法补充 .PHONY修饰 特殊符号替换 Makefile的推导过程 总结 前言&#xff1a; 在windows下&#xff0c;很多东西都是编译器直接帮你做…

im6ull学习总结(二)Framebuffer 应用编程

1 LCD操作原理 linux中通过framebuffer驱动程序来控制LCD。framebuffer中包含LCD的参数&#xff0c;大小为LCD分辨率xbpp。framebuffer 是一块内存 内存中保存了一帧图像。 关于图像的帧指的是在图像处理中&#xff0c;一帧&#xff08;Frame&#xff09;是指图像序列中的单个…

一篇文章带你轻松入门Python

Python基础 1. Hello World! Python命令行 假设你已经安装好了Python, 那么在命令提示符输入: python 将直接进入python。然后在命令行提示符>>>后面输入: >>>print(Hello World!) 可以看到&#xff0c;随后在屏幕上输出: print是一个常用函数&#xf…

python学习14

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

Analytify Pro Google Analytics Goals Addon谷歌分析目标插件

Analytify Pro Google Analytics Goals Addon谷歌分析目标插件是一款极其巧妙且具有开创性的工具&#xff0c;它赋予用户细致跟踪和全面分析其网站性能的卓越能力。有了这个非凡的插件&#xff0c;个人可以毫不费力地建立并认真监控他们的Google Analytics目标&#xff0c;从而…

du和df

du 和df 不一致的问题&#xff1a; 情况如下&#xff1a; innode 没有满 同事求助&#xff0c; 他在删掉一个很大的文件后&#xff0c; 磁盘空间依旧没释放。上去一看&#xff0c; 果然 df 看到磁盘空间占用依旧是100%&#xff0c;等等 du 看了一把&#xff0c;磁盘空间剩余很…

低延时视频技术的应用场景和挑战

编者按 无线网络对人们的生活产生了巨大的影响&#xff0c;而5G技术的引入将彻底改变我们与世界互联互通的方式。在5G时代&#xff0c;实现万物互联离不开低延时技术的应用。 LiveVideoStackCon 2023 深圳站邀请到秒点科技的CEO扶凯&#xff0c;为大家分享低延时技术在物联网、…

Impala大数据框架学习网站,大数据技能提升必备利器!

介绍&#xff1a;Impala是Cloudera开发的新型查询系统&#xff0c;它能够对存储在HDFS、HBaseImpala是Cloudera开发的新型查询系统&#xff0c;它能够对存储在HDFS、HBase以及S3上的数据进行快速的交互式SQL查询。此外&#xff0c;Impala与Hive使用了统一的存储系统、同样的元数…

什么是https证书?

HTTPS证书&#xff0c;也称为SSL&#xff08;Secure Sockets Layer&#xff09;证书或TLS&#xff08;Transport Layer Security&#xff09;证书&#xff0c;是一种数字证书&#xff0c;用于在网络上建立安全的加密连接。它的主要目的是确保在互联网上进行的数据传输的安全性和…

提升设计效率:全面了解如何使用Figma插件

Figma组件库包括颜色、字体、图标、按钮、阴影、圆角、间距等。当Figma组件库的样式和Figma组件达到一定数量时&#xff0c;将难以维护&#xff0c;设计和开发的对接成本将大大提高。Figma可以在同一母版下单独设置样式&#xff0c;而不影响与母版之前的关系&#xff0c;这是Sk…

w4操作系统之windows上创建隐藏用户

隐藏用户–在windows上创建隐藏用户 1.首先查看现有哪些用户。&#xff08;通过net user 命令&#xff09; 2.然后创建隐藏用户&#xff08;net user client$ 123 /add&#xff09; 此时出现报错信息。原因是登录用户没权限。需要用管理员的权限 3.用管理员身份运行cmd&am…

AspectJWeaver之Gadget分析

前言&#xff1a; 今天看了下ysoserial的AspectJWeaver方法&#xff0c;分析了下其是如何通过调用SimpleCache$StorableCachingMap来实现写文件&#xff0c;这里把分析的流程写下来&#xff1a; 首先我们要看下其所需要的jar包&#xff1a; <dependencies><dependen…

drf知识-08

Django之了解DRF框架 # 介绍&#xff1a;DRF全称 django rest framework # 背景&#xff1a; 在序列化与反序列化时&#xff0c;虽然操作的数据不尽相同&#xff0c;但是执行的过程却是相似的&#xff0c;也就是说这部分代码是可以复用简化编写的 增&#xff1a;校验请…

基于SSM实现的电动汽车充电网点管理系统

一、系统架构 前端&#xff1a;jsp | jquery | bootstrap | css 后端&#xff1a;spring | springmvc | jdbc 环境&#xff1a;jdk1.8 | mysql 二、代码及数据库 三、功能介绍 01. web端-首页 02. web端-登录 03. web端-注册 04. web端-我要充电 05. web端-个人中心-消…

网络编程『简易TCP网络程序』

&#x1f52d;个人主页&#xff1a; 北 海 &#x1f6dc;所属专栏&#xff1a; Linux学习之旅、神奇的网络世界 &#x1f4bb;操作环境&#xff1a; CentOS 7.6 阿里云远程服务器 文章目录 &#x1f324;️前言&#x1f326;️正文TCP网络程序1.字符串回响1.1.核心功能1.2.程序…

java设计模式学习之【解释器模式】

文章目录 引言解释器模式简介定义与用途实现方式 使用场景优势与劣势在Spring框架中的应用表达式解析示例代码地址 引言 在我们的日常生活中&#xff0c;语言的翻译和理解是沟通的关键。每种语言都有自己的语法规则&#xff0c;而翻译人员和计算机程序需要理解并遵循这些规则来…