首页
留言
友情链接
壁纸
更多
关于
Search
1
dockerfile怎么执行shell脚本(利用tail -f /dev/null命令防止container启动后退出)
4,942 阅读
2
channel常见的异常总结
4,259 阅读
3
支付宝支付配置开发流程
1,403 阅读
4
HTTP 协议中的Content-Encoding
1,251 阅读
5
Laravel底层原理(二) —— 契约(Contracts)
939 阅读
PHP
composer
laravel
swoole
Docker
Linux
Go
随笔
mysql
nginx
Search
标签搜索
gopher
Docker
PHP
dockerfile
通道
go
defer
alipay
支付
git
phpstorm
IDEA
web安全
漏洞
socket
Royal
累计撰写
35
篇文章
累计收到
0
条评论
首页
栏目
PHP
composer
laravel
swoole
Docker
Linux
Go
随笔
mysql
nginx
页面
留言
友情链接
壁纸
关于
搜索到
35
篇与
Royal
的结果
2022-04-21
【Gopher】go语言中的协程、通道(二)
并发的介绍1. 进程和线程进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。一个进程可以创建和撤销多个线程;同一个进程中的多个线程之间可以并发执行。2. 并发和并行多线程程序在一个核的cpu上运行,就是并发。多线程程序在多个核的cpu上运行,就是并行。并发并行3. 协程和线程协程:独立的栈空间,共享堆空间,调度由用户自己控制,本质上有点类似于用户级线程,这些用户级线程的调度也是自己实现的。线程:一个线程上可以跑多个协程,协程是轻量级的线程。并发主要由切换时间片来实现"同时"运行,并行则是直接利用多核实现多线程的运行,go可以设置使用核数,以发挥多核计算机的能力;goroutine 奉行通过通信来共享内存,而不是共享内存来通信。4. 管道 管道是协程之间交换数据的一个类型化的消息队列。在管道上的写操作和读操作已提前实现了互斥,并不需要显示的去给管道加锁(在访问共享数据时,也不应该去用加锁的方式。这会严重降低性能。)可以创建任意类型的管道,包括空接口类型。方法是ch:=make(chan dataType)。go使用协程1. 创建协程 使用go关键字可以去创建一个协程。但是需要注意的是,创建的协程会随着main函数的结束而结束,所以假如创建携程后main函数就执行结束了,可能所有协程都得不到运行。为了解决这个问题,在学习时可以让main函数sleep一段时间再结束运行。例如:func main(){ for i:=0;i<5;i++{//创建五个并发的协程 go print(i)//创建协程 } time.Sleep(1*time.Second)//让main函数睡一秒 } func print(n int){ for i:=0;i<20;i++{//每个协程会输出20个(编号,数字0-19)的组合 fmt.Print("(",n,i,")") } fmt.Println()//这只能代表有一次换行,并不能说是输出20个数据后换行。 } /* 输出: (0 0)(0 1)(1 0)(1 1)(1 2)(2 0)(2 1)(2 2)(2 3)(2 4)(2 5)(2 6)(2 7)(2 8)(2 9)(2 10)(2 11)(2 12)(2 13)(2 14)(2 15)(2 16)(2 17)(2 18)(2 19) (0 2)(0 3)(0 4)(0 5)(0 6)(0 7)(0 8)(0 9)(0 10)(0 11)(0 12)(0 13)(0 14)(0 15)(0 16)(0 17)(0 18)(0 19) (3 0)(3 1)(3 2)(3 3)(3 4)(3 5)(3 6)(3 7)(3 8)(3 9)(3 10)(1 3)(1 4)(1 5)(1 6)(1 7)(1 8)(1 9)(1 10)(1 11)(1 12)(1 13)(1 14)(1 15)(1 16)(1 17)(1 18)(1 19) (4 0)(3 11)(3 12)(3 13)(3 14)(3 15)(3 16)(3 17)(3 18)(3 19) (4 1)(4 2)(4 3)(4 4)(4 5)(4 6)(4 7)(4 8)(4 9)(4 10)(4 11)(4 12)(4 13)(4 14)(4 15)(4 16)(4 17)(4 18)(4 19) */可以看出,协程执行的顺序和创建的顺序并不一定相同。同时,一个携程也并不是从头到尾一次性执行完毕,他可能在函数体内部任意一条语句后就转去执行别的协程。因此,创建的五个协程内的5个fmt.Println()并不是每20个输出后换行,在最极端的情况下,可能出现输出连续输出100个元素后换行5次的情况。但在实际开发中,肯定不会使用sleep的方法让协程完成运行。应该使用sync包下的WaitGroup结构体中的Add() Done() Wait()三个函数去解决问题。2. 创建通道 和切片、map一样,通道也需要使用make创建。所以通道有下面两种创建方法:var ch1 chan int//先声明 ch1=make(chan int)//再分配空间 ch2:=make(chan int)//声明时分配3. 发送和接收数据 在向通道发送和接收数据时,都要用到<-操作符,该操作符的箭头指向为数据的流向。当发送数据时,使用msg:=<-ch来将通道中的数据发送到msg中。数据一旦从通道中取出,那么通道中就不会再存在这个数据了。向通道发送msg数据的方法为 ch<-msg。例子:func main(){ ch1:=make(chan int) go print(ch1)//创建输出数据的协程,将通道作为参数传入 go send(ch1)//创建产生数据的协程 time.Sleep(1*time.Second) } func send(ch chan int){ for i:=0;i<10;i++{ ch<-i//向通道中传入1-9 } } func print(ch chan int){ for i:=0;i<10;i++{ fmt.Print(<-ch," ")//从通道中将数据取出 } } /* 输出: 0 1 2 3 4 5 6 7 8 9 */但是需要注意的是,上面创建的通道都是缓冲为0的通道。这个意思是,如果有一个协程发送数据到通道时没有被其他协程立即接收,那么这个数据将会丢失。所以做法是make通道时增加他的缓冲。如:make(chan int,1)即创建一个缓冲为1的通道。下面这个程序将会出现死锁:func main(){ ch1:=make(chan int) ch1<-999//缓冲为0,发送到ch1之后,这个数据就会丢失。 go print(ch1)//这个协程等不到数据传入,所以会发生死锁。 time.Sleep(1*time.Second) } func print(ch chan int){ fmt.Println(<-ch) } /* 报错: all goroutines are asleep - deadlock! */如果将上述程序第二行的ch1:=make(chan int)改为ch1:=make(chan int,1)那么程序就会正常执行,输出999。4. 关闭通道 go中,使用close(ch)来关闭一个通道,释放资源。但即使是对一个已关闭的通道进行接收操作,也不会报错,这时就需要用到<-ch的第二个参数了。msg,ok:=<-ch才是一个通道正确的读取方法,如果通道已经被关闭,那么ok将会是false,否则为true。例子:func main(){ ch1:=make(chan int) go print(ch1) go send(ch1) time.Sleep(1*time.Second) } func send(ch chan int){ for i:=0;i<5;i++{ ch<-i } close(ch)//传入五个数据后就关闭通道 } func print(ch chan int){ for i:=0;i<20;i++{//连续读取二十个数据 v,ok:=<-ch fmt.Print("(",v,ok,")") } } /* 输出: (0 true)(1 true)(2 true)(3 true)(4 true)(0 false)(0 false)(0 false)(0 false)(0 false)(0 false)(0 false)(0 false)(0 false)(0 false)(0 false)(0 false)(0 false)(0 false)(0 false) */可以看出只有前五个数据是正确的。5. 迭代读取通道 如果使用for-range模式读取通道,则会自动检测通道是否被关闭。例如将上述例子的print函数替换为下面,即可自动检测通道是否被关闭了:func print(ch chan int){ for i:=range ch{ fmt.Print(i," ") } } /* 输出: 0 1 2 3 4 */6. select select的结构类似于switch-case结构,只不过他的case是通道。select语句选择一个已经准备好了的通道去执行,或是一直处于阻塞状态。例子:func main(){ ch1:=make(chan string) ch2:=make(chan string) go choose(ch1,ch2) rand.Seed(time.Now().UnixNano())//设置随机种子 for i:=0;i<5;i++{ c:=rand.Intn(2)//随机执行func1或func2 if c==0{ go func1(ch1) }else{ go func2(ch2) } } time.Sleep(1*time.Second) } func func1(ch chan string){ ch<-"11111111" } func func2(ch chan string){ ch<-"22222222" } func choose(ch1,ch2 chan string){ for{ select { //哪个通道准备好了,就执行哪个通道。 case v:=<-ch1: fmt.Println(v) case v:=<-ch2: fmt.Println(v) } } } /* 输出: 22222222 11111111 22222222 11111111 22222299 */上述程序一定会输出五条记录,因为不管是哪个通道准备好了数据,都会进行输出操作。如果choose函数写成下面这种,最极端的情况下一条数据都不会输出:func choose(ch1,ch2 chan string){ for{ fmt.Println(<-ch1) fmt.Println(<-ch2) } }
2022年04月21日
234 阅读
0 评论
0 点赞
2022-04-18
dockerfile怎么执行shell脚本(利用tail -f /dev/null命令防止container启动后退出)
最近在测试应用通过docker容器部署时发现,容器启动后无法自动启动NGINX和PHP程序,需要进入到容器内部来完成nginx和php的启动。具体的指令就是: docker exec -it 容器ID /bin/bash /usr/local/nginx/sbin/nginx #启动nginx /usr/local/php7/sbin/php-fpm #启动php ps -ef | grep 'nginx' ps -ef | grep 'php'通过以上指令才能完成容器内部的程序启动,那有没有办法在启动docker容器时自动启动内部程序运行呢?当然有!通过运行shell脚本的方式:我们在Dockerfile的同级目录下创建一个shell脚本,名字为start.sh编写start.sh文件#!/bin/bash /usr/local/php7/sbin/php-fpm /usr/local/nginx/sbin/nginx然后我们重新编写Dockerfile文件# base image FROM ci:latest # MAINTAINER MAINTAINER sangshuaidong <sangshuaidong@comleader.com.cn> # COPY COPY ci.localhost.com* /www/ COPY ["start.sh", "/root/start.sh"] RUN chmod -R 777 /www/ WORKDIR /root #CMD CMD ["/bin/bash","./start.sh"]注释:COPY脚本文件start.sh到我们容器内部的root目录下,然后设置工作目录为root,然后通过CMD命令来运行start.sh文件.我们先来看下CMD命令是用来做什么的?类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:CMD 在docker run 时运行。RUN 是在 docker build。作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。COMMAND为docker容器的默认启动命令,查看容器镜像的Dockerfile,一般体现为 CMD ["命令"] ,如 CMD ["/bin/bash"]每个容器都会有一个 pid 为 1 的进程,如果这个进程执行结束了,容器也就 close 了;COMMAND 为 /bin/bash, 说明这个容器的初始进程就是 bash 进程;默认情况下,docker logs <container_id> 也只会打印 pid 为 1 进程的输出现在我们打包镜像,运行一下容器看看是否可以正常启动php和nginx服务docker build -t ci:v3 . docker iamges启动容器:docker run -dit -p 8080:80 -p 443:443 -p 9000:9000 --privileged=true --name=civ3 ci:v3 docker ps 我们发现容器没有启动成功,这是为什么呢?我们分析下:container 刚起来的时候,用户可以通过 dockerfile 中的 CMD,ENTRYPOINT,或者直接在 docker run 后面接 comand,来指定 container 启动时执行的程序。如果指定的程序只是一个短暂的任务,比如 echo sorry。那么,sorry,container 在输出 “sorry” 之后,就退出了。可以通过 docker inspect 看到,container 状态变成了 Exited。docker build Dockerfile后,采用docker run –name xxx -d 运行容器,发现start.sh执行后容器就退出了,根本无法启动nginx和php。分析了一下docker的机制,一个docker容器同时只能管理一个进程,这个进程退出后,容器也就退出了。这并不意味着一个容器里只能同时运行一个进程(那样太浪费了),只是最后一个运行的进程不能退出。start.sh总结总结:容器中运行多个守护进程时,前面的进程要用后台方式运行(或添加 &),否则后面的服务无法启动容器中最后一个守护进程一定要用前台方式运行,否则start.sh退出,容器退出,所有的服务就白启动解决方法 可以利用tail -f /dev/null让容器一直处于runing状态,用CMD 执行一个脚本,在脚本中启动多个服务。例如我们要执行start.sh这个脚本,利用这个脚本启动主服务,并执行tail -f /dev/null:我们重新编写start.sh文件 只需要在末尾加上tail -f /dev/null#!/bin/bash /usr/local/php7/sbin/php-fpm /usr/local/nginx/sbin/nginx tail -f /dev/null然后我们重新按照上面流程打包镜像,启动容器即可!发现 php和nginx程序都是运行状态!那除了shell脚本方式运行 还有其他方式么?待更....
2022年04月18日
4,942 阅读
0 评论
0 点赞
2022-04-12
php设计模式(三)----工厂方法模式
应用场景:要实例化的对象充满不确定性可能会改变的时候;要创建的对象的数目和类型是未知的;结构:工厂方法UML图工厂方法模式包含如下角色:Product接口类:用于定义产品规范;具体的产品实现,例如ConcreateProductA、ConcreateProductB;抽象工厂类IFactory:用于规范工厂;具体产品创建的简单工厂,例如ConcreateFactoryA、ConcreateFactoryB。相比简单工厂 ,创建对象这件事不再交由一个类来创建:把简单工厂拆分,每个产品由专门的一个简单工厂来实现,每个简单工厂实现工厂接口类。这样实现在同一等级结构中,支持增加任意产品。代码实现:ICar.php定义产品规范<?php namespace SimpleFactory; interface ICar { public function driver(); } 具体产品实现<?php namespace SimpleFactory; class Benz implements ICar { public function driver() { echo 'benz driver.'; } } class Bmw implements ICar { public function driver() { echo 'bmw driver.'; } } 抽象工厂类IFactory<?php namespace Factory; interface IFactory { public static function makeCar(); } 具体工厂实现namespace Factory; class FactoryBenz implements IFactory { public static function makeCar() { return new Benz(); } } class FactoryBmw implements IFactory { public static function makeCar() { return new Bmw(); } }客户端使用<?php // 客户端 $car = FactoryBenz::makeCar(); $car->driver(); // 输出 benz driver.
2022年04月12日
145 阅读
0 评论
0 点赞
2022-04-09
php设计模式(二)----简单工厂模式
应用场景:工厂类负责创建的对象比较少;由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂;客户端只知道传入工厂类的参数,对于如何创建对象不关心;结构:简单工厂模式包含如下角色:Factory(工厂角色)工厂角色即工厂类,它是简单工厂模式的核心,负责实现创建所有实例的内部逻辑;工厂类可用直接被外界调用,创建所需要的产品对象;在工厂类中提供了静态的工厂方法factoryMethod(),它返回一个抽象产品类Product,所有的具体产品都是抽象产品的子类。Product(抽象产品角色)抽象产品角色是简单工厂模式所创建的所有对象的分类,负责描述所有实例所共有的公共接口,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个工厂方法,因为所有创建的具体产品对象都是其子类对象ConcreteProduct(具体产品角色)具体产品角色是简单工厂模式的创建目标,所有创建的对象都充当这个角色的某个具体类的实例。每一个具体产品角色都继承了抽象产品角色,需要实现定义在抽象产品中的抽象方法。代码实现:抽象产品角色Protuct.php<?php // 抽象产品角色 interface Product { public function play(); }具体产品角色productA.php<?php // 具体产品角色A require_once 'Product.php'; class productA implements Product { public function play() { // TODO: Implement play() method. echo 'productA play...'; } }具体产品角色productB.php<?php //具体产品角色B class productB implements Product { public function play() { // TODO: Implement play() method. echo 'productB play...'; } }工厂角色Factory.php<?php // 工厂类 require_once 'productA.php'; require_once 'productB.php'; class Factory { public function __construct($product) { if($product=='productA'){ echo '工厂生产productA'.PHP_EOL; $pro= new productA(); $pro->play(); }elseif ($product=='productB'){ echo '工厂生产productB'.PHP_EOL; $pro= new productB(); $pro->play(); }else{ echo '工厂暂不生产'; } } }.客户端使用<?php // 客户端 require_once 'Factory.php'; $factory=new Factory('productA'); // 输出productA play...
2022年04月09日
231 阅读
0 评论
0 点赞
2022-04-09
php设计模式(一)----单例模式
应用场景:数据库连接这种比较耗费资源的操作;我们希望整个应用只实例化一个;结构:4私1公或者3私一公(私有化重建方法非必须)私有化构造方法: 防止使用 new 创建多个实例;私有化克隆方法: 防止 clone 多个实例;私有化重建方法: 防止反序列化;私有化静态属性: 防止直接访问存储实例的属性;公有化静态方法。代码实现:class Singleton { //创建静态私有的变量保存该类对象 static private $instance; //防止使用new直接创建对象 private function __construct(){ } //防止使用clone克隆对象 private function __clone(){ } //防止反序列化 private function __wakeup(){ } static public function getInstance() { //判断$instance是否是Singleton的对象,不是则创建 if (!self::$instance instanceof self) { self::$instance = new self(); } return self::$instance; } public function test() { echo "我是一个单例模式"; } } $sing = Singleton::getInstance(); $sing->test(); $sing2 = new Singleton(); //Fatal error: Uncaught Error: Call to private Singleton::__construct() from invalid context in $sing3 = clone $sing; //Fatal error: Uncaught Error: Call to private Singleton::__clone() from context
2022年04月09日
250 阅读
0 评论
1 点赞
1
2
3
4
...
7