我的编程空间,编程开发者的网络收藏夹
学习永远不晚

LaravelORM+协程在Webman中的应用

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

LaravelORM+协程在Webman中的应用

这几天我在想如何在Webman框架中使用LaravelORM并支持协程。将两者结合起来,理论上可以兼顾高并发与开发效率。

实验目标

在Webman中集成LaravelORM协程版,并验证其性能和兼容性。

实验准备

环境配置

  • 操作系统:Ubuntu 20.04
  • PHP版本:PHP 8.1
  • Webman版本:最新版
  • PRipple引擎: 开发版

审计LaravelORM

Illuminate\Database\Connection

public function select($query, $bindings = [], $useReadPdo = true)
{
    return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) {
        if ($this->pretending()) {
            return [];
        }

        // For select statements, we'll simply execute the query and return an array
        // of the database result set. Each element in the array will be a single
        // row from the database table, and will either be an array or objects.
        $statement = $this->prepared(
            $this->getPdoForSelect($useReadPdo)->prepare($query)
        );

        $this->bindValues($statement, $this->prepareBindings($bindings));
        $statement->execute();
        return $statement->fetchAll();
    });
}

以select方法为例可以看到上述类中,Laravel将所有对\PDO的操作都封装在了Connection中
并提供了ConnectionInterface的抽象接口,这意味着如果实现了这个接口,就可以无缝的替换掉PDO逻辑

施工过程

我选用了AMPHP的MySQL客户端库amphp/mysql来实现这个接口

<?php declare(strict_types=1);

use Amp\Mysql\MysqlConfig;
use Amp\Mysql\MysqlConnectionPool;
use Amp\Mysql\MysqlTransaction;
use Closure;
use Exception;
use Fiber;
use Generator;
use Illuminate\Database\MySqlConnection;
use Throwable;

use function boolval;
use function in_array;
use function spl_object_hash;
use function trim;

class PConnection extends MySqlConnection
{
    private const ALLOW_OPTIONS = [
        'host',
        'port',
        'user',
        'password',
        'db',
        'charset',
        'collate',
        'compression',
        'local-infile',

        'username',
        'database'
    ];

    /*** @var MysqlConnectionPool */
    private MysqlConnectionPool $pool;

    /**
     * @param        $pdo
     * @param string $database
     * @param string $tablePrefix
     * @param array  $config
     */
    public function __construct($pdo, string $database = '', string $tablePrefix = '', array $config = [])
    {
        parent::__construct($pdo, $database, $tablePrefix, $config);
        $dsn = '';
        foreach ($config as $key => $value) {
            if (in_array($key, static::ALLOW_OPTIONS, true)) {
                if (!$value) {
                    continue;
                }

                $key = match ($key) {
                    'username' => 'user',
                    'database' => 'db',
                    default => $key
                };
                $dsn .= "{$key}={$value} ";
            }
        }
        $config     = MysqlConfig::fromString(trim($dsn));
        $this->pool = new MysqlConnectionPool($config);
        //                        if (isset($this->pdo)) {
        //                            unset($this->pdo);
        //                        }
    }

    /**
     * @return void
     */
    public function beginTransaction(): void
    {
        $transaction = $this->pool->beginTransaction();
        ;
        if ($fiber = Fiber::getCurrent()) {
            $this->fiber2transaction[spl_object_hash($fiber)] = $transaction;
        } else {
            $this->fiber2transaction['main'] = $transaction;
        }
    }

    /**
     * @return void
     * @throws Exception
     */
    public function commit(): void
    {
        if ($fiber = Fiber::getCurrent()) {
            $key = spl_object_hash($fiber);
        } else {
            $key = 'main';
        }

        if (!$transaction = $this->fiber2transaction[$key] ?? null) {
            throw new Exception('Transaction not found');
        }

        $transaction->commit();
        unset($this->fiber2transaction[$key]);
    }

    /**
     * @param $toLevel
     * @return void
     * @throws Exception
     */
    public function rollBack($toLevel = null): void
    {
        if ($fiber = Fiber::getCurrent()) {
            $key = spl_object_hash($fiber);
        } else {
            $key = 'main';
        }

        if (!$transaction = $this->fiber2transaction[$key] ?? null) {
            throw new Exception('Transaction not found');
        }

        $transaction->rollback();
        unset($this->fiber2transaction[$key]);
    }

    /**
     * @var MysqlTransaction[]
     */
    private array $fiber2transaction = [];

    /**
     * @param Closure $callback
     * @param int     $attempts
     * @return mixed
     * @throws Throwable
     */
    public function transaction(Closure $callback, $attempts = 1): mixed
    {
        $this->beginTransaction();
        try {
            $result = $callback($this->getTransaction());
            $this->commit();
            return $result;
        } catch (Throwable $e) {
            $this->rollBack();
            throw $e;
        }
    }

    /**
     * @return MysqlTransaction|null
     */
    private function getTransaction(): MysqlTransaction|null
    {
        if ($fiber = Fiber::getCurrent()) {
            $key = spl_object_hash($fiber);
        } else {
            $key = 'main';
        }

        if (!$transaction = $this->fiber2transaction[$key] ?? null) {
            return null;
        }

        return $transaction;
    }

    /**
     * @param string $query
     * @param array  $bindings
     * @param bool   $useReadPdo
     * @return array
     */
    public function select($query, $bindings = [], $useReadPdo = true): mixed
    {
        return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) {
            if ($this->pretending()) {
                return [];
            }

            $statement = $this->pool->prepare($query);
            return $statement->execute($this->prepareBindings($bindings));
        });
    }

    /**
     * @param string $query
     * @param array  $bindings
     * @return bool
     */
    public function statement($query, $bindings = []): bool
    {
        return $this->run($query, $bindings, function ($query, $bindings) {
            if ($this->pretending()) {
                return [];
            }

            $statement = $this->getTransaction()?->prepare($query) ?? $this->pool->prepare($query);
            return boolval($statement->execute($this->prepareBindings($bindings)));
        });
    }

    /**
     * 针对数据库运行 select 语句并返回所有结果集。
     *
     * @param string $query
     * @param array  $bindings
     * @param bool   $useReadPdo
     * @return array
     */
    public function selectResultSets($query, $bindings = [], $useReadPdo = true): array
    {
        return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) {
            if ($this->pretending()) {
                return [];
            }

            $statement = $this->pool->prepare($query);
            $result    = $statement->execute($this->prepareBindings($bindings));
            $sets      = [];

            while ($result = $result->getNextResult()) {
                $sets[] = $result;
            }

            return $sets;
        });
    }

    /**
     * 针对数据库运行 select 语句并返回一个生成器。
     *
     * @param string $query
     * @param array  $bindings
     * @param bool   $useReadPdo
     * @return Generator
     */
    public function cursor($query, $bindings = [], $useReadPdo = true): Generator
    {
        while ($record = $this->select($query, $bindings, $useReadPdo)) {
            yield $record;
        }
    }

    /**
     * 运行 SQL 语句并获取受影响的行数。
     *
     * @param string $query
     * @param array  $bindings
     * @return int
     */
    public function affectingStatement($query, $bindings = []): int
    {
        return $this->run($query, $bindings, function ($query, $bindings) {
            if ($this->pretending()) {
                return 0;
            }
            // 对于更新或删除语句,我们想要获取受影响的行数
            // 通过该语句并将其返回给开发人员。我们首先需要
            // 执行该语句,然后我们将使用 PDO 来获取受影响的内容。
            $statement = $this->pool->prepare($query);
            $result    = $statement->execute($this->prepareBindings($bindings));
            $this->recordsHaveBeenModified(
                ($count = $result->getRowCount()) > 0
            );
            return $count;
        });
    }

    /**
     * @return void
     */
    public function reconnect()
    {
        //TODO: 无事可做
    }

    /**
     * @return void
     */
    public function reconnectIfMissingConnection()
    {
        //TODO: 无事可做
    }
}

取代工厂

实现了Connection之后我们还有Hook住DatabaseManager的工厂方法`

return new class ($app) extends ConnectionFactory {
    /**
     * Create a new connection instance.
     *
     * @param string      $driver
     * @param PDO|Closure $connection
     * @param string      $database
     * @param string      $prefix
     * @param array       $config
     * @return SQLiteConnection|MariaDbConnection|MySqlConnection|PostgresConnection|SqlServerConnection|Connection
     *
     */
    protected function createConnection($driver, $connection, $database, $prefix = '', array $config = []): SQLiteConnection|MariaDbConnection|MySqlConnection|PostgresConnection|SqlServerConnection|Connection
    {
        return match ($driver) {
            'mysql' => new PConnection($connection, $database, $prefix, $config),
            'mariadb' => new MariaDbConnection($connection, $database, $prefix, $config),
            'pgsql' => new PostgresConnection($connection, $database, $prefix, $config),
            'sqlite' => new SQLiteConnection($connection, $database, $prefix, $config),
            'sqlsrv' => new SqlServerConnection($connection, $database, $prefix, $config),
            default => throw new InvalidArgumentException("Unsupported driver [{$driver}]."),
        };
    }
}

为了验证上述无缝耦合的最终效果,我准备将它安装到Webman

接入过程

我封装了一个Database类,用于Hook住Laravel的DatabaseManager

use Illuminate\Container\Container;
use Illuminate\Database\Capsule\Manager;
use Illuminate\Database\DatabaseManager;
use Illuminate\Events\Dispatcher;
use Illuminate\Pagination\Cursor;
use Illuminate\Pagination\CursorPaginator;
use Illuminate\Pagination\Paginator;
use Psc\Drive\Laravel\Coroutine\Database\Factory;
use function class_exists;
use function config;
use function get_class;
use function method_exists;
use function request;

class Database extends Manager
{
    /**
     * @return void
     */
    public static function install(): void
    {
        /**
         * 判断是否安装Webman
         */
        if (!class_exists(\support\Container::class)) {
            return;
        }

        /**
         * 判断是否曾被Hook
         */
        if (isset(parent::$instance) && get_class(parent::$instance) === Database::class) {
            return;
        }

        /**
         * Hook webman LaravelDB
         */
        $config      = config('database', []);
        $connections = $config['connections'] ?? [];
        if (!$connections) {
            return;
        }
        $app = Container::getInstance();

        /**
         * Hook数据库连接工厂
         */
        $capsule = new Database($app);
        $default = $config['default'] ?? false;

        if ($default) {
            $defaultConfig = $connections[$config['default']] ?? false;
            if ($defaultConfig) {
                $capsule->addConnection($defaultConfig);
            }
        }

        foreach ($connections as $name => $config) {
            $capsule->addConnection($config, $name);
        }

        if (class_exists(Dispatcher::class) && !$capsule->getEventDispatcher()) {
            $capsule->setEventDispatcher(\support\Container::make(Dispatcher::class, [Container::getInstance()]));
        }

        // Set as global
        $capsule->setAsGlobal();
        $capsule->bootEloquent();

        // Paginator
        if (class_exists(Paginator::class)) {
            if (method_exists(Paginator::class, 'queryStringResolver')) {
                Paginator::queryStringResolver(function () {
                    $request = request();
                    return $request?->queryString();
                });
            }
            Paginator::currentPathResolver(function () {
                $request = request();
                return $request ? $request->path() : '/';
            });
            Paginator::currentPageResolver(function ($pageName = 'page') {
                $request = request();
                if (!$request) {
                    return 1;
                }
                $page = (int)($request->input($pageName, 1));
                return $page > 0 ? $page : 1;
            });
            if (class_exists(CursorPaginator::class)) {
                CursorPaginator::currentCursorResolver(function ($cursorName = 'cursor') {
                    return Cursor::fromEncoded(request()->input($cursorName));
                });
            }
        }

        parent::$instance = $capsule;
    }

    /**
     * Hook Factory
     * @return void
     */
    protected function setupManager(): void
    {
        $factory       = new Factory($this->container);
        $this->manager = new DatabaseManager($this->container, $factory);
    }
}

实践运行结果

为了更直观的展现协程的效果,我将webman-worker数量改为了1,并且在每次请求中都会进行数据库查询

初始化控制器

 /**
 * @param Request $request
 * @return string
 */
public function index(Request $request): string
{
    // 手动Hook调DatabaseManager
    Database::install();

    // 记录执行时间
    $startTime = microtime(true);

    // 模拟一个耗时1s的查询
    $result    = Db::statement('SELECT SLEEP(1);');

    // 记录结束时间
    $endTime   = microtime(true);

    // 输出结果
    return "{$startTime} - {$endTime}";
}

启动单元测试

<?php declare(strict_types=1);

namespace Tests;

use GuzzleHttp\Client;
use PHPUnit\Framework\TestCase;
use Psc\Plugins\Guzzle\PHandler;
use function P\async;
use function P\tick;

class CoroutineTest extends TestCase
{
    public function test_main(): void
    {
        $client = new Client(['handler' => new PHandler(['pool'=>0])]);
        for ($i = 0; $i < 100; $i++) {
            async(function () use ($client, $i) {
                $response        = $client->get('http://127.0.0.1:8787/');
                $responseContent = $response->getBody()->getContents();
                echo "Request $i: $responseContent\n";
            });
        }
        tick();
        $this->assertEquals(1, 1);
    }
}

最终输出结果

可以看到每个请求都确实耗时一秒,但100个请求都在一秒内完成了

Request 0: 1723015194.3121 - 1723015195.4183
Request 1: 1723015194.3389 - 1723015195.4193
Request 2: 1723015194.339 - 1723015195.4196
Request 3: 1723015194.3391 - 1723015195.4187
Request 4: 1723015194.3391 - 1723015195.4198
Request 5: 1723015194.3392 - 1723015195.42
Request 6: 1723015194.3393 - 1723015195.4202
Request 7: 1723015194.3394 - 1723015195.4204
Request 8: 1723015194.3394 - 1723015195.4588
Request 9: 1723015194.3395 - 1723015195.4595
Request 10: 1723015194.3395 - 1723015195.4626
Request 11: 1723015194.3396 - 1723015195.4633
Request 12: 1723015194.3397 - 1723015195.4653
Request 13: 1723015194.3398 - 1723015195.4658
Request 14: 1723015194.3398 - 1723015195.4688
Request 15: 1723015194.3399 - 1723015195.4726
Request 16: 1723015194.34 - 1723015195.4735
Request 17: 1723015194.34 - 1723015195.4774
Request 18: 1723015194.3401 - 1723015195.48
Request 19: 1723015194.3402 - 1723015195.4805
Request 20: 1723015194.3402 - 1723015195.4816
Request 21: 1723015194.3403 - 1723015195.4818
Request 22: 1723015194.3404 - 1723015195.4862
Request 23: 1723015194.3404 - 1723015195.4911
Request 24: 1723015194.3405 - 1723015195.4915
Request 25: 1723015194.3406 - 1723015195.4917
Request 26: 1723015194.3406 - 1723015195.4919
Request 27: 1723015194.3408 - 1723015195.4921
Request 28: 1723015194.3408 - 1723015195.4923
Request 29: 1723015194.3409 - 1723015195.4925
Request 30: 1723015194.3409 - 1723015195.4933
Request 31: 1723015194.341 - 1723015195.4935
Request 32: 1723015194.341 - 1723015195.4936
Request 33: 1723015194.3411 - 1723015195.4938
Request 34: 1723015194.3412 - 1723015195.494
Request 35: 1723015194.3412 - 1723015195.4941
Request 36: 1723015194.3413 - 1723015195.4943
Request 37: 1723015194.3414 - 1723015195.4944
Request 38: 1723015194.3414 - 1723015195.4946
Request 39: 1723015194.3416 - 1723015195.4947
Request 40: 1723015194.3417 - 1723015195.4949
Request 41: 1723015194.3418 - 1723015195.495
Request 42: 1723015194.342 - 1723015195.5174
Request 43: 1723015194.3421 - 1723015195.518
Request 44: 1723015194.3423 - 1723015195.5184
Request 45: 1723015194.3425 - 1723015195.5191
Request 46: 1723015194.3426 - 1723015195.5194
Request 48: 1723015194.3429 - 1723015195.5215
Request 50: 1723015194.3433 - 1723015195.5219
Request 51: 1723015194.3435 - 1723015195.5221
Request 47: 1723015194.3428 - 1723015195.5225
Request 49: 1723015194.3431 - 1723015195.523
Request 52: 1723015194.3436 - 1723015195.5265
Request 53: 1723015194.3437 - 1723015195.5268
Request 54: 1723015194.3439 - 1723015195.527
Request 55: 1723015194.344 - 1723015195.5275
Request 56: 1723015194.3443 - 1723015195.5282
Request 57: 1723015194.3444 - 1723015195.5314
Request 58: 1723015194.3445 - 1723015195.5316
Request 59: 1723015194.3445 - 1723015195.5318
Request 60: 1723015194.3446 - 1723015195.5323
Request 61: 1723015194.3448 - 1723015195.5324
Request 62: 1723015194.3449 - 1723015195.5326
Request 63: 1723015194.345 - 1723015195.5328
Request 64: 1723015194.3451 - 1723015195.533
Request 65: 1723015194.3453 - 1723015195.5331
Request 66: 1723015194.3455 - 1723015195.5437
Request 67: 1723015194.3456 - 1723015195.5441
Request 69: 1723015194.3458 - 1723015195.5443
Request 70: 1723015194.3459 - 1723015195.5445
Request 71: 1723015194.346 - 1723015195.5448
Request 72: 1723015194.3464 - 1723015195.5451
Request 68: 1723015194.3457 - 1723015195.5456
Request 73: 1723015194.3471 - 1723015195.5508
Request 74: 1723015194.3475 - 1723015195.551
Request 75: 1723015194.3478 - 1723015195.5512
Request 76: 1723015194.3482 - 1723015195.5516
Request 77: 1723015194.3486 - 1723015195.5518
Request 78: 1723015194.3489 - 1723015195.5542
Request 79: 1723015194.3491 - 1723015195.5545
Request 80: 1723015194.3492 - 1723015195.5549
Request 81: 1723015194.3493 - 1723015195.5605
Request 82: 1723015194.3493 - 1723015195.561
Request 83: 1723015194.3494 - 1723015195.5633
Request 84: 1723015194.3494 - 1723015195.5638
Request 85: 1723015194.3495 - 1723015195.5641
Request 86: 1723015194.3496 - 1723015195.5661
Request 87: 1723015194.3496 - 1723015195.5678
Request 88: 1723015194.3497 - 1723015195.5681
Request 89: 1723015194.3499 - 1723015195.5684
Request 90: 1723015194.35 - 1723015195.5685
Request 91: 1723015194.3501 - 1723015195.5756
Request 92: 1723015194.3502 - 1723015195.5758
Request 93: 1723015194.3504 - 1723015195.576
Request 94: 1723015194.3505 - 1723015195.5768
Request 95: 1723015194.3506 - 1723015195.577
Request 96: 1723015194.3508 - 1723015195.5772
Request 97: 1723015194.3509 - 1723015195.5774
Request 98: 1723015194.3509 - 1723015195.5777
Request 99: 1723015194.351 - 1723015195.5781

结论

通过上述实践,我们可以看到LaravelORM与Webman中使用协程是非常具有可行性的,
并且在高并发&慢查询场景下,协程的优势也在此得到了充分的体现

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

LaravelORM+协程在Webman中的应用

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

LaravelORM+协程在Webman中的应用

这几天我在想如何在Webman框架中使用LaravelORM并支持协程。将两者结合起来,理论上可以兼顾高并发与开发效率。实验目标在Webman
LaravelORM+协程在Webman中的应用
2024-08-07

Golang协程在实际项目中的应用

golang协程通过goroutine实现并发执行:创建协程:使用goroutine关键词创建协程,其本质是共享内存的执行函数。并发处理请求:在分布式文件系统中,使用协程并行处理来自多个客户端的并发请求,提升性能。并行读取文件:在一个协程中
Golang协程在实际项目中的应用
2024-04-15

协程在Linux中的高效应用实例

Nginx服务器:Nginx是一个高性能的Web服务器和反向代理服务器,它利用协程来处理大量的并发连接请求。通过使用协程,Nginx可以有效地处理大量的并发连接,提高服务器的性能和响应速度。Redis数据库:Redis是一个高性能的内存数据
协程在Linux中的高效应用实例
2024-08-06

Linux协程在实时系统中的应用

在实时系统中,Linux协程可以用来实现高效的任务调度和多线程编程。通过使用协程,可以避免线程切换的开销,提高系统的性能和响应速度。此外,协程还可以帮助程序员更容易地编写复杂的并发程序,提高系统的可维护性和可扩展性。在实时系统中,Linu
Linux协程在实时系统中的应用
2024-08-07

Linux协程在物联网设备中的应用

Linux协程在物联网设备中的应用越来越广泛,主要体现在以下几个方面:资源利用效率:协程可以实现轻量级线程切换,避免了传统线程切换时需要保存和恢复整个线程上下文的开销,因此在资源有限的物联网设备上能更有效地利用系统资源。高并发性能:通过协程
Linux协程在物联网设备中的应用
2024-08-07

Linux协程在大数据处理中的应用

Linux协程在大数据处理中的应用主要体现在以下几个方面:高效的并发处理:Linux协程可以实现轻量级的并发处理,可以在一个线程内同时处理多个任务,减少线程切换的开销,提高处理效率。资源利用率高:通过协程的调度和管理,可以更好地利用系统资源
Linux协程在大数据处理中的应用
2024-08-06

并发和协程在Golang API设计中的应用

并发和协程在 go api 设计中可用于:高性能处理:同时处理多个请求以提高性能。异步处理:使用协程异步处理任务(例如发送电子邮件),释放主线程。流处理:使用协程高效处理数据流(例如数据库读取)。并发和协程在 Golang API 设计中的
并发和协程在Golang API设计中的应用
2024-05-07

Go 协程在游戏开发中的应用是什么?

协程是一种轻量级线程,在游戏开发中广泛应用于 ai 控制、物理模拟、网络通信和渲染等方面,其中 ai 行为的网络化是 goroutine 应用的典型案例。Go 协程在游戏开发中的应用协程概述协程是一种轻量级线程,与传统线程类似,协程也可
Go 协程在游戏开发中的应用是什么?
2024-05-21

Go 协程在区块链技术中的应用是什么?

在区块链技术中,利用 go 协程可提高性能和可扩展性。具体应用场景包括并行处理区块验证、加速网络通信、管理智能合约执行和优化共识算法。例如,我们可以使用协程并行获取最新区块,从而显著提高性能。Go 协程在区块链技术中的应用简介Gorou
Go 协程在区块链技术中的应用是什么?
2024-05-21

Golang协程在人工智能领域的应用

协程在人工智能领域的应用广泛,可提高应用程序性能,有效利用多核 cpu。具体来说,协程可用于创建轻量级线程并发执行耗时操作,无需阻塞主线程,如本案例中创建的 10 个协程,模拟耗时操作,利用协程并行处理,有效提高程序效率。Go 协程在人工智
Golang协程在人工智能领域的应用
2024-04-15

Go 协程在 FinTech 领域的应用是什么?

go 协程在 fintech 中的应用包括异步任务处理、事件处理、实时流处理和微服务架构。实战案例包含异步交易处理和事件处理,其中协程用于并发执行任务并通过通道进行通信。Go 协程在 FinTech 领域的应用简介Go 协程是一种轻量级
Go 协程在 FinTech 领域的应用是什么?
2024-05-21

Golang中线程与协程的区别及应用

Golang中线程与协程的区别及应用Golang是一种开发效率高、并发性能强大的编程语言,其中线程(goroutine)和协程(thread)是其并发编程的关键概念。在Golang中,goroutine是一种轻量级线程,由Go语言运行时管
Golang中线程与协程的区别及应用
2024-02-29

WebSocket协议在在线投票应用中的实际应用经验分享

引言:随着互联网的普及和技术的不断进步,越来越多的应用程序在实现实时通信和交互功能时选择了WebSocket协议。本文将以在线投票应用为例,介绍WebSocket协议在该应用中的实际应用经验,并提供具体的代码示例。一、背景介绍在线投票应用是
2023-10-21

如何在Golang中使用协程

这篇文章将为大家详细讲解有关如何在Golang中使用协程,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。什么是golanggolang 是Google开发的一种静态强类型、编译型、并发型,并具
2023-06-14

怎么在python3协程中使用asyncio

怎么在python3协程中使用asyncio?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Python主要用来做什么Python主要应用于:1、Web开发;2、
2023-06-14

怎么在python协程中调用Task

怎么在python协程中调用Task?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Python的优点有哪些1、简单易用,与C/C++、Java、C# 等传统语言相比,Pytho
2023-06-14

Golang协程池的实现与应用

这篇文章主要介绍了Golang协程池的实现与应用,使用协程池的好处是减少在创建和销毁协程上所花的时间以及资源的开销,解决资源不足的问题,需要详细了解可以参考下文
2023-05-19

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录