golang——gorountine+channal

本文介绍了如何在Go语言中使用goroutine和channel进行并发编程,涉及WaitGroup协调、单向与双向通道的应用、多路复用以及协程错误处理。

golang——gorountine+channel

  1. 基本使用
package main

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

var wg sync.WaitGroup

func putNum(intChan chan int) {
	for i := 1; i <= 200; i++ {
		intChan <- i
	}
	close(intChan)
	wg.Done()
}

func primeNum(intChan chan int, primeChan chan int, exitChan chan bool) {
	for num := range intChan {
		flag := true
		if num != 1 {
			for i := 2; i < num; i++ {
				if num%i == 0 {
					flag = false
					break
				}
			}
			if flag {
				primeChan <- num
			}
		}

	}
	exitChan <- true
	wg.Done()
}

func printPrime(primeChan chan int) {
	for v := range primeChan {
		fmt.Println("素数是:", v)
	}
	wg.Done()
}

func main() {
	intChan := make(chan int, 200)
	primeChan := make(chan int, 200)
	exitChan := make(chan bool, 16)
	wg.Add(1)
	go putNum(intChan)
	for i := 0; i < 16; i++ {
		wg.Add(1)
		go primeNum(intChan, primeChan, exitChan)
	}
	wg.Add(1)
	go printPrime(primeChan)

	wg.Add(1)
	go func() {
		for i := 0; i < 16; i++ {
			<-exitChan
		}
		close(primeChan)
		wg.Done()
	}() //匿名执行函数
	wg.Wait()
}

快速知识点

  1. 每开启一个协程之前wg.Add(1),方法结束之后wg.Done()
  2. 当多个协程对同一个管道进行写入和读出的操作时,读出很快但是会等待写入完成
  3. 管道如果要用range进行遍历,则需要将管道关闭Close(),否则会报deadclock死锁错误,如果用for进行遍历不会出错但是建议还是要将管道关闭
  4. 被关闭的管道是可以被读的但是不能被写入
  5. 主线程比协程执行要快,所以需要设置wg.Wait()进行等待
  1. 单向通道
//单向通道,只能读
ch1 := make(<-chan int ,3)
//只能写
ch2 := make(chan<- int, 3)
  1. 多路复用
for{
	select {
		case v:= <-intChan:
			fmt.Println(v)
		case v:= <-stringChan:
			fmt.Println(v)
		default:
			fmt.Println("读取完毕")
			return 
	}
}

多路复用的时候不需要关闭管道

  1. 解决协程出现的Panic
//需要recover()宕机恢复,并且返回异常,只能在defer函数中调用
defer func(){
	if err := recover();err!=nuil{
		fmt.Println("出问题啦")
	}
}()
以下是一种使用 Golang 转码插件和 Java 微服务实现视频流转码的可能方法: ### 整体架构设计 将整个视频流转码系统拆分为多个微服务,其中 Java 微服务负责业务逻辑的处理,如接收视频流请求、管理任务队列、与外部系统交互等;Golang 转码插件负责具体的视频转码操作,利用 Golang 的高效性能来完成转码任务。 ### Java 微服务部分 1. **接收视频流请求**:使用 Spring Boot 框架搭建 Java 微服务,创建 RESTful 接口来接收视频流的转码请求。可以使用 Spring Web 模块来实现这部分功能。 ```java import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @RestController public class VideoTranscodingController { @PostMapping("/transcode") public String transcodeVideo(@RequestBody VideoTranscodingRequest request) { // 处理转码请求 return "Transcoding task submitted"; } } class VideoTranscodingRequest { private String videoUrl; private String targetFormat; // Getters and Setters public String getVideoUrl() { return videoUrl; } public void setVideoUrl(String videoUrl) { this.videoUrl = videoUrl; } public String getTargetFormat() { return targetFormat; } public void setTargetFormat(String targetFormat) { this.targetFormat = targetFormat; } } ``` 2. **任务管理**:使用消息队列(如 RabbitMQ 或 Kafka)来管理转码任务。将接收到的转码请求发送到消息队列中,等待 Golang 转码插件消费。 ```java import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class TaskManagementService { @Autowired private RabbitTemplate rabbitTemplate; public void submitTranscodingTask(VideoTranscodingRequest request) { rabbitTemplate.convertAndSend("transcoding_queue", request); } } ``` ### Golang 转码插件部分 1. **消费消息队列**:使用 Golang 的 RabbitMQ 客户端库(如 `amqp`)来消费消息队列中的转码任务。 ```go package main import ( "log" "github.com/streadway/amqp" ) func main() { conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/") if err != nil { log.Fatalf("Failed to connect to RabbitMQ: %v", err) } defer conn.Close() ch, err := conn.Channel() if err != nil { log.Fatalf("Failed to open a channel: %v", err) } defer ch.Close() q, err := ch.QueueDeclare( "transcoding_queue", // name false, // durable false, // delete when unused false, // exclusive false, // no-wait nil, // arguments ) if err != nil { log.Fatalf("Failed to declare a queue: %v", err) } msgs, err := ch.Consume( q.Name, // queue "", // consumer true, // auto-ack false, // exclusive false, // no-local false, // no-wait nil, // args ) if err != nil { log.Fatalf("Failed to register a consumer: %v", err) } forever := make(chan bool) go func() { for d := range msgs { // 处理转码任务 log.Printf("Received a message: %s", d.Body) // 调用转码库进行转码 transcodeVideo(string(d.Body)) } }() log.Printf(" [*] Waiting for messages. To exit press CTRL+C") <-forever } func transcodeVideo(task string) { // 使用 Golang 转码库(如 FFmpeg 的 Golang 绑定)进行转码 // 示例代码省略 } ``` 2. **视频转码**:使用 FFmpeg 的 Golang 绑定(如 `go-ffmpeg`)来进行视频转码操作。 ```go package main import ( "github.com/u2takey/ffmpeg-go" "log" ) func transcodeVideo(videoUrl, targetFormat string) { err := ffmpeg.Input(videoUrl). Output(targetFormat, ffmpeg.KwArgs{"c:v": "libx264"}). OverWriteOutput().ErrorToStdOut().Run() if err != nil { log.Fatalf("Failed to transcode video: %v", err) } log.Printf("Video transcoded successfully to %s", targetFormat) } ``` ### 数据交互与结果反馈 Java 微服务可以通过监听 Golang 转码插件发送的消息来获取转码结果,并将结果返回给客户端。可以使用消息队列或其他通信机制来实现这部分功能。 ### 总结 通过上述步骤,可以使用 Golang 转码插件和 Java 微服务实现视频流转码。Java 微服务负责业务逻辑的处理和任务管理,Golang 转码插件负责具体的视频转码操作,两者通过消息队列进行通信,实现了系统的解耦和高效运行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值