一、进程、线程、协程之间的联系和区别

swoole4开始支持了类似go的协程,以下是进程、线程、协程之间的联系。

1、进程

经典定义:一个执行中程序的实例。系统中的每个程序都运行在某个进程的上下文中。(-摘自 CSAPP)进程是系统资源分配的最小单位。

2、线程(thread)

线程就是运行在进程上下文中的逻辑流。线程是操作系统能够进行运算调度的最小单位。

3、协程

相对 子例程而言,协程更为一般和灵活,但在实践中使用没有子例程那样广泛。根据维基百科对子例程的描述:是一个大型程序中的某部分代码,由一个或多个语句块组成。它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性。我可以将子例程理解为一个函数。

4、协程与线程的区别

  • 一个线程可以多个协程,一个进程也可以单独拥有多个协程。
  • 线程进程都是同步机制,而协程则是异步。
  • 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态。
  • 线程是抢占式,而协程是非抢占式的,所以需要用户自己释放使用权来切换到其他协程,因此同一时间其实只有一个协程拥有运行权,相当于单线程的能力。
  • 协程并不是取代线程, 而且抽象于线程之上, 线程是被分割的CPU资源, 协程是组织好的代码流程, 协程需要线程来承载运行, 线程是协程的资源, 但协程不会直接使用线程, 协程直接利用的是执行器(Interceptor), 执行器可以关联任意线程或线程池, 可以使当前线程, UI线程, 或新建新程。
  • 线程是协程的资源。协程通过Interceptor来间接使用线程这个资源。
  • 极高的执行效率:因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显;
  • 不需要多线程的锁机制:因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

废话有点密了哈哈



二、本文将采用宝塔+thinkphp6+swoole搭建



具体流程如下:

三、根据这个创建一个swoolews指令,如下:

1、安装宝塔(可略过):
宝塔面板下载,免费全能的服务器运维软件
2、安装thinkphp6(可略过):
安装 · ThinkPHP6.0完全开发手册 · 看云
3、创建自定义指令:

php快速搭建swoole玩转协程 - 图1

php快速搭建swoole玩转协程 - 图2

php快速搭建swoole玩转协程 - 图3

‘swoolews’ => ‘app\command\Swoolews’,

php快速搭建swoole玩转协程 - 图4

4、直接去swoole官方文档(抄代码!哈哈!)

Swoole4 文档:https://wiki.swoole.com/#/start/start_ws_server

php快速搭建swoole玩转协程 - 图5

php快速搭建swoole玩转协程 - 图6

  1. <?php
  2. declare (strict_types = 1);
  3. namespace app\command;
  4. use think\console\Command;
  5. use think\console\Input;
  6. use think\console\input\Argument;
  7. use think\console\input\Option;
  8. use think\console\Output;
  9. class Swoolews extends Command
  10. {
  11. protected function configure()
  12. {
  13. // 指令配置
  14. $this->setName('swoolews')
  15. ->setDescription('the swoolews command');
  16. }
  17. protected function execute(Input $input, Output $output)
  18. {
  19. // 指令输出
  20. $output->writeln('swoolews');
  21. //创建WebSocket Server对象,监听0.0.0.0:9502端口
  22. $ws = new \Swoole\WebSocket\Server('0.0.0.0', 9501);
  23. //监听WebSocket连接打开事件
  24. $ws->on('Open', function ($ws, $request) {
  25. $ws->push($request->fd, "hello, welcome\n");
  26. });
  27. //监听WebSocket消息事件
  28. $ws->on('Message', function ($ws, $frame) {
  29. echo "Message: {$frame->data}\n";
  30. $ws->push($frame->fd, "server: {$frame->data}");
  31. });
  32. //监听WebSocket连接关闭事件
  33. $ws->on('Close', function ($ws, $fd) {
  34. echo "client-{$fd} is closed\n";
  35. });
  36. $ws->start();
  37. }
  38. }

5、在项目目录下启动ws服务并测试(注意!记得服务器和宝塔开启9501端口,咱们服务配置的是9501端口)

php快速搭建swoole玩转协程 - 图7

测试ws网站链接:在线websocket测试-online tool-postjson(http://coolaf.com/tool/chattest)

随便发送个消息:

php快速搭建swoole玩转协程 - 图8

php快速搭建swoole玩转协程 - 图9

有回应就说明没有问题喽,当然上述代码可能不易于维护,你也可以根据swoole官方文档给的基础知识改写一下:
Swoole4 文档

6、测试协程

协程文档链接:Swoole4 文档(https://wiki.swoole.com/#/start/coroutine)

php快速搭建swoole玩转协程 - 图10

php快速搭建swoole玩转协程 - 图11

<?php
declare (strict_types = 1);

namespace app\command;

use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use Swoole\Coroutine;
use function Swoole\Coroutine\go;
class Swoolews extends Command
{
    protected function configure()
{
        // 指令配置
        $this->setName('swoolews')
            ->setDescription('the swoolews command');
    }

    protected function execute(Input $input, Output $output)
{
        // 指令输出
        $output->writeln('swoolews');

        //创建WebSocket Server对象,监听0.0.0.0:9502端口
        $ws = new \Swoole\WebSocket\Server('0.0.0.0', 9501);

        //监听WebSocket连接打开事件
        $ws->on('Open', function ($ws, $request) {
            $ws->push($request->fd, "hello, welcome\n");
        });

        //监听WebSocket消息事件
        $ws->on('Message', function ($ws, $frame) {
            echo "Message: {$frame->data}\n";
            //协程测试
            for($i=0;$i<10;$i++) {
                go(function () use ($ws ,$frame, $i) {

                    for ($n = 100; $n--;) {
                        usleep(1000);
                    }
                });
            }
            $ws->push($frame->fd, "server: 完成");
        });

        //监听WebSocket连接关闭事件
        $ws->on('Close', function ($ws, $fd) {
            echo "client-{$fd} is closed\n";
        });

        $ws->start();


    }
}

重启服务

php快速搭建swoole玩转协程 - 图12

php快速搭建swoole玩转协程 - 图13

效果还是不错的!

7、swoole协程与go协程的区别

go语言协程相对智能很多,使用的是MPG模式调度协程~ 简单说就是产生的所有协程其它的线程是有空就能去执行的,是多cpu调度的,相当于有一个协程池,空闲的cpu会去池子里执行协程任务,相比swoole的单cpu调用更有效地利用系统资源。可以方便的实现API的并行处理,达到处理效率的最大化。

所以咱们也不去夸大swoole的能力,真正要说协程比较强大的还是goroutine,这个咱不犟。

swoole协程还是在io操作上能提高效率,其他情况还是考虑php多进程吧!