并发、并行、进程、线程概念

 

  • 并发(Concurrency):

 

    • 定义: 并发是指系统能够同时处理多个任务,但不一定是同时执行。在一个并发系统中,任务可以被切分成小的时间片段,交替地执行,从而给人一种同时执行的感觉。

    • 实现:可以通过多进程、多线程、协程等方式来实现并发
    • 通信:为了保证数据的一致性,安全性,进程间的协调,消息传递等
  • 高并发:
    • 定义:服务器的处理器是有限的,但是用户请求是巨大的,这样的处理就是高并发

 

  • 并行(Parallelism):

 

    • 定义: 并行是指系统同时执行多个任务,每个任务都在不同的处理单元上独立运行。在并行系统中,多个处理器或核心同时执行不同的指令,以加快整体任务的完成速度。。

  • 进程线程
    •  进程是操作系统中一个独立的执行单元,有独立的内存空间,进程之间相互独立
    •  线程是是程的一个执行单元,共享相同的内存空间和系统资源,但拥有独立的栈空间      
    • 实例:多个用户请求服务器。。
      • 多线程: 通常,使用多线程更为常见,因为线程共享同一进程的地址空间,可以更方便地共享数据,减少了线程之间的通信和同步的复杂性。在Web服务器等场景中,多线程的模型可以通过一个主线程监听用户请求,每当有请求到达时,创建一个新的线程来处理该请求。这使得服务器能够同时服务多个用户。
      • 多进程: 也可以使用多进程来处理多个用户请求,每个请求分配给一个独立的进程进行处理。这样可以实现更高度的隔离,每个进程拥有独立的内存空间,减少了进程之间的共享数据的复杂性。但进程间通信的开销相对较高,因此在某些情况下,使用多进程可能不如多线程高效。              

 

 

go的并发                                                                                                                              

  • 定义:主要机制是goroutine和channel(通道)
  • 实现:go 关键字用于在一个新的goroutine中执行一个函数,它允许你的程序以并发的方式执行代码
  • Goroutines(轻量级线程): Go语言的并发模型的核心是goroutine。Goroutine是一种轻量级的线程,由Go运行时系统管理。与传统的线程相比,goroutine的创建和销毁开销很小,因此可以创建大量的goroutine,而不会导致系统负担过重。
// 创建一个通道
ch := make(chan int)

// 启动一个goroutine发送数据
go func() {
    ch <- 42 // 将数据发送到通道
}()

// 在主goroutine中接收数据
data := <-ch // 从通道中接收数据

  

  • Channel(通道): Goroutines之间通信是通过channel完成的。通道是一种类型,用于在goroutines之间传递数据。通道提供了同步的机制,确保一个goroutine发送的数据能够被另一个goroutine正确接收
  • Select语句: Go语言的select语句用于处理多个通道操作。它使得一个goroutine可以等待多个通道操作中的任意一个完成
  • Mutex(互斥锁): Go语言也提供了传统的互斥锁机制,用于在多个goroutine之间共享数据时保护共享资源的一致性

 通道

   <- 符号用于通道(channel)的发送和接收操作

ch <- value  // 发送 value 到通道 ch

data := <-ch  // 从通道 ch 中接收数据,并将其赋值给变量 data

data := <- ch <- value 从右向左

 sync.WaitGroup

  等待一组并发任务完成后再继续执行下一步,WaitGroup 就提供了一种简单的同步机制来实现这个目的

  在线程的开始和结束,写行那两个参数

package main

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

func main() {
	var wg sync.WaitGroup

	for i := 1; i <= 3; i++ {
		wg.Add(1)
		go processTask(i, &wg)
	}

	// 等待所有 goroutine 完成
	wg.Wait()

	fmt.Println("All tasks have been completed.")
}

func processTask(taskID int, wg *sync.WaitGroup) {
	defer wg.Done()

	// 模拟任务的耗时操作
	time.Sleep(2 * time.Second)

	fmt.Printf("Task %d has been completed.\n", taskID)
}

 案例

 

    案例

使用了sync.WaitGroup来等待所有的goroutine任务完成。每次启动goroutine时,通过wg.Add(1)增加WaitGroup的计数,而在createPDF函数中的defer语句中调用wg.Done()来减少计数。
这样主函数就可以通过wg.Wait()等待所有的goroutine任务完成。这样的修改使得下载和生成PDF的过程可以并发执行,提高了程序的效率
package main

import (
	"fmt"
	"github.com/jung-kurt/gofpdf"
	"image"
	"image/jpeg"
	"io/ioutil"
	"net/http"
	"sync"
)

// createPDF 通过给定的图片URL列表创建一个PDF文件
// 参数imageURLs: 包含图片URL的切片
// 参数outputPDF: 输出的PDF文件名(不包含文件扩展名)
func createPDF(imageURLs []string, outputPDF string, wg *sync.WaitGroup) {
	// 创建一个PDF文档对象
	pdf := gofpdf.New("P", "mm", "Letter", "")

	// 遍历图片URL列表
	for _, imageURL := range imageURLs {
		// 发送HTTP请求获取图片
		response, err := http.Get(imageURL)
		if err != nil {
			fmt.Printf("Error downloading image: %v\n", err)
			continue
		}
		defer response.Body.Close()

		// 检查HTTP响应状态码
		if response.StatusCode == http.StatusOK {
			// 解码图片
			img, _, err := image.Decode(response.Body)
			if err != nil {
				fmt.Printf("Error decoding image: %v\n", err)
				continue
			}

			// 将解码后的图片添加到PDF页面
			pdf.AddPage()

			// 创建一个临时文件保存解码后的图片
			tempFile, err := ioutil.TempFile("", "temp-image-*.jpg")
			if err != nil {
				fmt.Printf("Error creating temp file: %v\n", err)
				continue
			}
			defer tempFile.Close()

			// 保存解码后的图片到临时文件
			jpeg.Encode(tempFile, img, nil)

			// 使用ImageOptions设置图像参数
			opts := gofpdf.ImageOptions{
				ImageType: "jpg",
				ReadDpi:   false,
			}

			// 将解码后的图片添加到PDF页面
			pdf.ImageOptions(tempFile.Name(), 0, 0, 210, 297, false, opts, 0, "")
		}
	}

	// 添加PDF文件扩展名
	outputPDF = outputPDF + ".pdf"
	// 将PDF保存到文件
	pdf.OutputFileAndClose(outputPDF)

	// 通知WaitGroup任务完成
	wg.Done()
}

func main() {
	for {
		var inputString, outputName string
		fmt.Print("请输入密钥,按回车结束输入(输入 q 退出): ")
		fmt.Scanln(&inputString)

		if inputString == "q" {
			break
		}
		// 格式化字符串生成一个新的字符串
		baseURL := fmt.Sprintf("https://pic03.sogoucdn.com/s3/a/201069/docTranslate/%s/transedImg", inputString)
		var successURLs []string
		var wg sync.WaitGroup

		for i := 0; i < 50; i++ {
			numberStr := fmt.Sprintf("%03d", i)
			currentURL := baseURL + numberStr + ".jpg"

			response, err := http.Get(currentURL)
			if err != nil {
				fmt.Printf("Error checking image existence: %v\n", err)
				break
			}
			defer response.Body.Close()

			if response.StatusCode == http.StatusOK {
				fmt.Println("成功", currentURL)
				successURLs = append(successURLs, currentURL)
			} else {
				break
			}
		}

		// 增加WaitGroup的计数,表示有多少个goroutine任务需要等待
		wg.Add(1)

		fmt.Print("请输入翻译后的文件名: ")
		fmt.Scanln(&outputName)

		// 启动一个goroutine执行createPDF函数
		go createPDF(successURLs, outputName, &wg)

		// 等待所有goroutine任务完成
		wg.Wait()

		fmt.Println("翻译已完成")
	}
}

  

python的并发

  • 定义:有多线程、多进程、协程
  • 多线程: 在Python中,使用threading模块可以创建和管理线程。每个线程都是独立的执行流,但它们共享相同的全局解释器锁(Global Interpreter Lock,简称GIL)。这意味着在任何给定的时刻,只有一个线程能够执行Python字节码。因此,多线程主要用于IO密集型任务,而不适用于CPU密集型任务
  • 多进程: 使用multiprocessing模块可以创建和管理多个进程,每个进程都有自己独立的解释器和GIL,因此可以充分利用多核处理器执行CPU密集型任务
  • 协程: 协程是一种轻量级的线程,Python中通过asyncio模块提供了对协程的支持。协程使用asyncawait关键字,允许异步非阻塞的IO操作,从而提高程序的并发性能

 

python并发和go的区别

  • 全局解释器锁(GIL):
    • Python: Python解释器中存在GIL,它是一个全局锁,限制了同一时刻只能有一个线程执行Python字节码。多核CPU也不能充分利用其多核性能。
    • Go: Go语言没有全局解释器锁,允许多个goroutines并发执行。这使得Go在处理并发和并行任务时更为高效,尤其对于CPU密集型的工作负载。

 

posted on 2023-12-20 15:29  黑逍逍  阅读(6)  评论(0编辑  收藏  举报