Golang多线程排序实现快速高效地处理大规模数据

 更新时间:2023年05月11日 10:10:20   作者:Luyoungs  
Golang多线程排序是一种快速高效地处理大规模数据的方法,通过使用Golang的协程和通道,可以将排序任务分配到多个线程中并行处理,提高了排序的效率和速度,需要详细了解可以参考下文

前言

本案例实现一个多线程排序算法,能够对给定的整数数组进行排序,使用 goroutines 对其进行并发化优化。

随机数生成器

func randProduce(randNums chan []int, wg *sync.WaitGroup) {
	for i := 0; i < 100; i++ {
		go rand1(randNums, wg)
	}
}
func rand1(randNums chan []int, wg *sync.WaitGroup) {
	r := rand.New(rand.NewSource(time.Now().Unix()))
	int1000 := make([]int, 1000000)
	for i := 0; i < 1000000; i++ {
		int1000[i] = r.Intn(1000000)
	}
	randNums <- int1000
	wg.Done()
}

使用goroutines并发地对各个子数组进行排序

func sort0(randNums chan []int, sortNums chan []int, wg *sync.WaitGroup) {
	for i := 0; i < 100; i++ {
		go sort2(randNums, sortNums, wg)
	}
}
func sort2(randNums chan []int, sortNums chan []int, wg *sync.WaitGroup) {
	int1000_Old := <-randNums
	sort.Ints(int1000_Old)
	sortNums <- int1000_Old
	wg.Done()
}

合并已排序的子数组得到最终排序结果

func mergeAll(sortNums chan []int, wg *sync.WaitGroup) []int {
	defer wg.Done()
	temp2 := <-sortNums
	var temp1 []int
	for i := 1; i <= 99; i++ {
		temp1 = make([]int, 1000000*i+1000000)
		copy(temp1, temp2)
		temp1 = merge(temp1, 1000000*i+1000000, <-sortNums, 1000000)
		temp2 = make([]int, 1000000*i+1000000)
		copy(temp2, temp1)
	}
	return temp2
}
func merge(nums1 []int, m int, nums2 []int, n int) []int {
	temp := make([]int, m)
	copy(temp, nums1)
	t, j := 0, 0 //t为temp的索引,j为nums2的索引
	for i := 0; i < len(nums1); i++ {
		if t >= len(temp) {
			nums1[i] = nums2[j]
			j++
			continue
		}
		if j >= n {
			nums1[i] = temp[t]
			t++
			continue
		}
		if nums2[j] <= temp[t] {
			nums1[i] = nums2[j]
			j++
		} else {
			nums1[i] = temp[t]
			t++
		}
	}
	return nums1
}

main 函数控制流程

func main() {
	fmt.Println("开始运行!")
	start := time.Now() // 获取当前时间
	wg := sync.WaitGroup{}
	wg.Add(201)
	randNums := make(chan []int, 100)
	sortNUms := make(chan []int, 100)
	go randProduce(randNums, &wg)
	go sort0(randNums, sortNUms, &wg)
	go mergeAll(sortNUms, &wg)
	wg.Wait()
	// fmt.Println(l)
	elapsed := time.Since(start)
	fmt.Println("该函数执行完成耗时:", elapsed)
}

思路

本案例采用了两个 channel,分别存储产生的的随机数slice和排好顺序的 slice,每一个 slice大小为 100 万,一共一百个 slice,也就是一亿个数据。

randNums := make(chan []int, 100)
	sortNUms := make(chan []int, 100)

程序一边产生随机数,一边将产生的随机数randNums发送到 sort 函数进行排序,排好顺序后将数据发送到sortNUms。这两个流程可以并行计算,因此:

go randProduce(randNums, &wg)
	go sort0(randNums, sortNUms, &wg)

合并也可以参与到并行计算之中,多加一个信号量就好:

go mergeAll(sortNUms, &wg)

运行结果:

(base) luliang@shenjian Sort % go build SortRoutine.go

(base) luliang@shenjian Sort % ./SortRoutine

开始运行!

该函数执行完成耗时: 50.317081625s

性能比较

可以写一个单线程的排序,但是数据产生还是多线程的:

package main
import (
	"fmt"
	"math/rand"
	"sort"
	"time"
)
func main() {
	fmt.Println("开始运行!")
	start := time.Now() // 获取当前时间
	randNums := make(chan int, 10000)
	go randProduce1(randNums)
	randNums1 := make([]int, 100000000)
	for i := 0; i < 100000000; i++ {
		randNums1[i] = <-randNums
	}
	sort.Ints(randNums1)
	elapsed := time.Since(start)
	fmt.Println("该函数执行完成耗时:", elapsed)
}
func randProduce1(randNums chan int) {
	for i := 0; i < 10000; i++ {
		go rand2(randNums)
	}
}
func rand2(randNums chan int) {
	r := rand.New(rand.NewSource(time.Now().Unix()))
	for i := 0; i < 10000; i++ {
		randNums <- r.Intn(10000000)
	}
}

运行结果为:

(base) luliang@shenjian Sort % go build SortRoutine1.go

(base) luliang@shenjian Sort % ./SortRoutine1

开始运行!

该函数执行完成耗时: 54.869565792s

可以看到两种方法消耗的时间差不多,这是因为数据量还是太小,多线程生成数据、排序、以及合并开辟了大量的协程,这个会消耗一定的时间。

到此这篇关于Golang多线程排序实现快速高效地处理大规模数据的文章就介绍到这了,更多相关Golang多线程排序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go内存分配之结构体优化技巧

    Go内存分配之结构体优化技巧

    这篇文章主要为大家详细介绍了Go语言内存分配之结构体优化技巧的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-11-11
  • 高效封禁:利用Go封装功能,提升封禁操作效率

    高效封禁:利用Go封装功能,提升封禁操作效率

    在网络安全领域,封禁操作是一项重要的任务,用于阻止恶意行为和保护系统安全,而利用Go语言封装功能可以提升封禁操作的效率,Go语言具有高效的并发性能和简洁的语法,使得开发者可以快速构建高性能的封禁系统,
    2023-10-10
  • Go语言生成UUID的利器(github.com/google/uuid)

    Go语言生成UUID的利器(github.com/google/uuid)

    UUID是确保每个元素唯一性的重要工具,Go语言虽然在标准库中没有直接提供UUID生成功能,但可以通过安装github.com/google/uuid库来实现,本文就来介绍一下,感兴趣的可以了解一下
    2024-11-11
  • Golang中fsnotify包监听文件变化的原理详解

    Golang中fsnotify包监听文件变化的原理详解

    Golang提供了一个强大的fsnotify包,它能够帮助我们轻松实现文件系统的监控,本文将深入探讨fsnotify包的原理,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-12-12
  • Golang协程池gopool设计与实现

    Golang协程池gopool设计与实现

    本文主要介绍了Golang协程池gopool设计与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • GoLang调用链可视化go-callvis使用介绍

    GoLang调用链可视化go-callvis使用介绍

    与链路追踪(Tracing)不同,Tracing关注复杂的分布式环境中各个服务节点间的调用关系,主要用于服务治理。而我们本次探索的代码调用链路则是代码方法级别的调用关系,主要用于代码设计
    2023-02-02
  • Golang Http请求返回结果处理

    Golang Http请求返回结果处理

    本文主要介绍了Golang Http请求返回结果处理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • golang gorm 操作mysql及gorm基本用法

    golang gorm 操作mysql及gorm基本用法

    golang 官方的那个操作mysql的有点麻烦所以就使用了gorm,下面就gorm的使用做下简单介绍,感兴趣的朋友跟随小编一起看看吧
    2018-11-11
  • Go1.18新特性对泛型支持详解

    Go1.18新特性对泛型支持详解

    这篇文章主要为大家介绍了Go1.18新特性对泛型支持详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • Golang 如何实现函数的任意类型传参

    Golang 如何实现函数的任意类型传参

    这篇文章主要介绍了Golang 实现函数的任意类型传参操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04

最新评论