golang-操作系统-同步&管道&匿名管道&内存管道

十、同步

1. 计数器案例,同一个程序开俩个 进程A和进程B。并发执行 把数据库中符合条件的记录迁移到磁盘。用计数器记录 当前被处理的最大行号。
   	1. 第一步,读取计数器的值C
   	2. 第二步,从数据库中读取 C+10000 行数据。
   	3. 第三步, 遍历符合条件的数据,并形成新的数据集合
   	4. 第四步,将新的数据集合 存储到哦指定目录文件中。
   	5. 第五步,把计数器值+10000
   	6. 检查数据是否全部处理完成。是则退出,否则从第一步开始。
2. 原子操作,把执行过程中不能被中断的操作 为原子操作。
3. 临界区,把只能串行化访问或执行的资源或代码为 临界区。所有的系统调用都属于原子操作。
4. 原子操作和 临界区 是不同的概念,临界区 要求 一个访问者在临界区时,其他访问者不饿能被放进来。原子操作是不能被中断。原子操作需要芯片级别的支持,当今的cpu都提供了对原子的操作。

十一、管道

  1. 管道是一种半双工的通讯方式,它只能被用于父进程与子进程,以及同祖先的子进程之间的通讯。

  2. shell命令 用到管道,ps aux | grep go

  3. shell 为每个命令创建一个进程,然后把左边的命令 标准输出管道 与右边的命令的 标准输入 连接起来。

  4. golang通过exec.command 执行命令+exec.command().StdoutPipe()以管道形式输出 到缓冲区bytes.Buffer

    	//1.输入定义系统命令
    	cmd0 := exec.Command("echo", "-n", "my first command from golang.")
    	//2.定义命令执行标准输出管道
    	stdout0, _ := cmd0.StdoutPipe()
    	//3.启动执行系统命令
    	if err := cmd0.Start(); err != nil {
    		log.Fatalf("command err:%s", err.Error())
    	}
    	
    	var outputBuf bytes.Buffer
    	for {
    		output0 := make([]byte, 5)
    		//4.通过标准输出管道 读出数据  打印
    		n, err := stdout0.Read(output0)
    		if err != nil {
    			if err == io.EOF {
    				break
    			} else {
    				log.Fatalf("can not read data from pipe:%s", err.Error())
    			}
    		}
    		//5.当n< 5时表示数据读取完毕,当n>=5表示数据没有完全读完。需要for循环读取,直到err == io.EOF
    		if n > 0 {
    			outputBuf.Write(output0[:n])
    		}
    	}	
    	log.Printf("data from pipe:%s\n", output0[:n])
    
  5. golang通过exec.command 执行命令+exec.command().StdoutPipe()以管道形式输出 +通过带缓冲区的读取器输出

    //1.输入定义系统命令
       	cmd0 := exec.Command("echo", "-n", "my first command from golang.")
       	//2.定义命令执行标准输出管道
       	stdout0, _ := cmd0.StdoutPipe()
       	//3.启动执行系统命令
       	if err := cmd0.Start(); err != nil {
       		log.Fatalf("command err:%s", err.Error())
       	}
       	//4.定义一个缓冲读取器,
       	outputBuf := bufio.NewReader(stdout0)
       	//5.第二个参数表示该行 是否被读完
       	output0, _, err := outputBuf.ReadLine()
       	if err != nil {
       		log.Fatalf("can not read data from pipe:%s", err.Error())
       	}
    	log.Printf("data from pipe:%s\n", string(output0))
    
  6. golang通过stdout1 := exec.Command().StdoutPipe()以管道形式输出 + 通过 bufio.NewReader(stdout1).WriteTo(stdout2) 读取,并写入第二个管道stdout2:= exec.Command().StdoutPipe()

    //1.执行俩个命令
    	cmd1 := exec.Command("ps", "aux")
    	cmd2 := exec.Command("grep", "nginx")
    	//2.第一个命令以输出管道
    	stdout1, err := cmd1.StdoutPipe()
    	if err != nil {
    		log.Fatalf("stdoutpipe1 err:%v", err)
    	}
    	//3.启动第一个命令的执行
    	if err := cmd1.Start(); err != nil {
    		log.Fatalf("cmd1 start err:%v", err)
    	}
    	//3.第一个管道内容传递给缓冲区1
    	outputBuf1 := bufio.NewReader(stdout1)
    	//4.定义第二个命令的输入管道
    	stdin2, err := cmd2.StdinPipe()
    	if err != nil {
    		log.Fatalf("stdin2 err:%v", err)
    	}
    	//5.把第一个缓冲区1 写入第二个输入管道2
    	_, err = outputBuf1.WriteTo(stdin2)
    	if err != nil {
    		log.Fatalf("outputBuf1 write to stdin2 err:%v", err)
    	}
    	//6.定义第二个命令标准输出缓冲区2
    	var outputBuf2 bytes.Buffer
    	cmd2.Stdout = &outputBuf2
    	if err := cmd2.Start(); err != nil {
    		log.Fatalf("cmd2 start err:%v", err)
    	}
    	//7.关闭第二个输入管道
    	if err := stdin2.Close(); err != nil {
    		log.Fatalf("cmd2 close err:%v", err)
    	}
    	//8.等待所有运行结束
    	if err := cmd2.Wait(); err != nil {
    		log.Fatalf("cmd2 wait err:%v", err)
    	}
    	log.Printf("outputBuf2 :%s", outputBuf2.String())
    	/**
    	结果:
    	2022/09/17 20:27:11 outputBuf2 :
    	root       1084  0.0  0.0  46504  1208 ?        Ss   19:50   0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
    	nginx      1086  0.0  0.0  49044  2052 ?        S    19:50   0:00 nginx: worker process
    	nginx      1091  0.0  0.0  49044  2052 ?        S    19:50   0:00 nginx: worker process
    	nginx      1094  0.0  0.0  49044  2052 ?        S    19:50   0:00 nginx: worker process
    	nginx      1096  0.0  0.0  49044  2052 ?        S    19:50   0:00 nginx: worker process
    
    	*/
    
  7. 以上是匿名管道,相对应的是命名管道,任何程序都可以通过命名管道交换数据。命名管道以文件形式存在于文件系统中

  8. //命名管道默认是阻塞的,单向的。
    //1.创建命名管道myfifo1
    mkfifo -m 644 myfifo1
    //2.阻塞等待 myfifo1 命名管道数据到来。tee从标准输入设备读取数据,将内容输出到标准输出设备,并写入文件。
    tee dst.log < myfifo1 &
    //3. 把dst.log内容写入管道myfifo1
    cat dst.log > myfifo1
    
    1. 注意,命名管道 默认会 将其中一端 还未就绪的时候阻塞 另一端的进程
    //注意,命名管道 默认会 将其中一端 还未就绪的时候阻塞 另一端的进程。
    	//1. os.pipe() 输出俩个结构,输入端;输出端 *os.File
    	reader, writer, _ := os.Pipe()
    	var wg sync.WaitGroup
    	wg.Add(1)
    	go func(file *os.File) {
    		defer file.Close()
    		defer wg.Done()
    		if _, err := file.Write([]byte("i love you!")); err != nil {
    			log.Fatalf("write pipe err:%v", err)
    		}
    		log.Printf("writer pipe succ.\n")
    	}(writer)
    	wg.Add(1)
    	go func(file *os.File) {
    		defer file.Close()
    		defer wg.Done()
    		output := make([]byte, 512)
    		n, err := file.Read(output)
    		if err != nil {
    			log.Fatalf("reader pipe err:%v", err)
    		}
    		log.Printf("reader pipe:%s", string(output[:n]))
    	}(reader)
    	wg.Wait()
    	/**
    		结果:
    	2022/09/17 20:54:17 writer pipe succ.
    	2022/09/17 20:54:17 reader pipe:i love you!
    
    	*/
    
    1. 匿名管道会在管道缓冲区被写满后 使写数据的 进程被阻塞。命名管道会在一段就绪前 阻塞 另一端的进程。

    2. 当有多个输入端同时写入数据的时候得考虑原子性,操作系统提供的管道使不提供原子操作支持的。

    3. 内存管道 go 提供的io.Pipe()

    4. go channel 和 pipeline区别

      不同channelpipe
      结构stream of a go typestream of bytes
      平台specific type in golangunix like
      缓冲区depend on circumstancesalways buffered
      特点connect between goroutinebetween two process(std.in/out)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
go实战微服务分布式系统(distributed system)是建立在网络之上的软件系统。正是因为软件的特性,所以分布式系统具有高度的内聚性和透明性。因此,网络和分布式系统之间的区别更多的在于高层软件(特别是操作系统),而不是硬件。在一个分布式系统中,一组独立的计算机展现给用户的是一个统一的整体,就好像是一个系统似的。系统拥有多种通用的物理和逻辑资源,可以动态的分配任务,分散的物理和逻辑资源通过计算机网络实现信息交换。系统中存在一个以全局的方式管理计算机资源的分布式操作系统。通常,对用户来说,分布式系统只有一个模型或范型。在操作系统之上有一层软件中间件(middleware)负责实现这个模型。一个著名的分布式系统的例子是万维网(World Wide Web),在万维网中,所有的一切看起来就好像是一个文档(Web页面)一样。 [1] 在计算机网络中,这种统一性、模型以及其中的软件都不存在。用户看到的是实际的机器,计算机网络并没有使这些机器看起来是统一的。如果这些机器有不同的硬件或者不同的操作系统,那么,这些差异对于用户来说都是完全可见的。如果一个用户希望在一台远程机器上运行一个程序,那么,他必须登陆到远程机器上,然后在那台机器上运行该程序。 [1] 分布式系统和计算机网络系统的共同点是:多数分布式系统是建立在计算机网络之上的,所以分布式系统与计算机网络在物理结构上是基本相同的。 [1] 他们的区别在于:分布式操作系统的设计思想和网络操作系统是不同的,这决定了他们在结构、工作方式和功能上也不同。网络操作系统要求网络用户在使用网络资源时首先必须了解网络资源,网络用户必须知道网络中各个计算机的功能与配置、软件资源、网络文件结构等情况,在网络中如果用户要读一个共享文件时,用户必须知道这个文件放在哪一台计算机的哪一个目录下;分布式操作系统是以全局方式管理系统资源的,它可以为用户任意调度网络资源,并且调度过程是“透明”的。当用户提交一个作业时,分布式操作系统能够根据需要在系统中选择最合适的处理器,将用户的作业提交到该处理程序,在处理器完成作业后,将结果传给用户。在这个过程中,用户并不会意识到有多个处理器的存在,这个系统就像是一个处理器一样。 [1] 内聚性是指每一个数据库分布节点高度自治,有本地的数据库管理系统。透明性是指每一个数据库分布节点对用户的应用来说都是透明的,看不出是本地还是远程。在分布式数据库系统中,用户感觉不到数据是分布的,即用户不须知道关系是否分割、有无副本、数据存于哪个站点以及事务在哪个站点上执行等。  什么是微服务?维基上对其定义为:一种软件开发技术- 面向服务的体系结构(SOA)架构样式的一种变体,将应用程序构造为一组松散耦合的服务。在微服务体系结构中,服务是细粒度的,协议是轻量级的。微服务(或微服务架构)是一种云原生架构方法,其中单个应用程序由许多松散耦合且可独立部署的较小组件或服务组成。这些服务通常● 有自己的堆栈,包括数据库和数据模型;● 通过REST API,事件流和消息代理的组合相互通信;● 和它们是按业务能力组织的,分隔服务的线通常称为有界上下文。尽管有关微服务的许多讨论都围绕体系结构定义和特征展开,但它们的价值可以通过相当简单的业务和组织收益更普遍地理解:● 可以更轻松地更新代码。● 团队可以为不同的组件使用不同的堆栈。● 组件可以彼此独立地进行缩放,从而减少了因必须缩放整个应用程序而产生的浪费和成本,因为单个功能可能面临过多的负载。 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小哥(xpc)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值