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

 

  • 并发(Concurrency):

 

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

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

 

  • 并行(Parallelism):

 

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

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

 

 

go的并发                                                                                                                              

  • 定义:主要机制是goroutine和channel(通道)
  • 实现:go 关键字用于在一个新的goroutine中执行一个函数,它允许你的程序以并发的方式执行代码
  • Goroutines(轻量级线程): Go语言的并发模型的核心是goroutine。Goroutine是一种轻量级的线程,由Go运行时系统管理。与传统的线程相比,goroutine的创建和销毁开销很小,因此可以创建大量的goroutine,而不会导致系统负担过重。
1
2
3
4
5
6
7
8
9
10
// 创建一个通道
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)的发送和接收操作

1
2
3
ch <- value  // 发送 value 到通道 ch
 
data := <-ch  // 从通道 ch 中接收数据,并将其赋值给变量 data<br><br>data := <- <strong>ch</strong> <- value 从右向左

 sync.WaitGroup

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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)
}

 案例

 

    案例

1
使用了sync.WaitGroup来等待所有的goroutine任务完成。每次启动goroutine时,通过wg.Add(1)增加WaitGroup的计数,而在createPDF函数中的defer语句中调用wg.Done()来减少计数。<br>这样主函数就可以通过wg.Wait()等待所有的goroutine任务完成。这样的修改使得下载和生成PDF的过程可以并发执行,提高了程序的效率
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
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   黑逍逍  阅读(54)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!



点击右上角即可分享
微信分享提示