Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

windows swoole-cli-v4.8.13-cygwin-x64 使用协程监听的Channel数据然后插入数据库,插入没几条就报错了! #5331

Open
Dadiaojin opened this issue May 20, 2024 · 5 comments

Comments

@Dadiaojin
Copy link

环境:windows10 安装包:swoole-cli-v4.8.13-cygwin-x64.zip
数据库结构:

CREATE TABLE `cache` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `msg` longtext,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

swoole运行代码:


<?php


use function Swoole\Coroutine\run;
use function Swoole\Coroutine\go;
use Swoole\Coroutine\Channel;
use Swoole\Coroutine\WaitGroup;


class MyCurl
{
    public static $fail_arr = [];

    public function curl_test($set)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1?set=' . $set);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $result = curl_exec($ch);
        // var_dump(curl_getinfo($ch));
        // var_dump(curl_error($ch));
        curl_close($ch);
        return $result;
    }
}

class MyUseMysql
{
    public static $instert_arr = [];
    private static $conn;

    public function __construct()
    {
        if (empty(self::$conn)) {
            $swoole_mysql = new Swoole\Coroutine\MySQL();
            $swoole_mysql->connect([
                'host' => '127.0.0.1',
                'port' => 3306,
                'user' => 'root',
                'password' => 'root',
                'database' => 'test',
            ]);
            self::$conn = $swoole_mysql;
        }
    }

    public function setMsg($msg)
    {
        $sql = "INSERT INTO `cache` (`msg`) VALUES ('$msg');";
        self::$conn->begin();
        self::$conn->query($sql);
        self::$conn->commit();
    }
}


run(function () {

    // 创建管道
    $channel = new Channel(1);

    // 协程数量
    $go_count = 100;

    // 模拟数据
    $pc_arr = [];
    for ($pc = 1; $pc <= 250; $pc++) {
        $pc_arr[] = $pc;
    }
    // 分成100份模拟数据(100个协程)
    $chunks = array_chunk($pc_arr, ceil(count($pc_arr) / $go_count));

    //等待协程
    $wg = new WaitGroup();
    // 100个协程生产数据
    foreach ($chunks as $chunk_key => $chunk_value) {
        $wg->add();
        go(function () use ($chunk_key, $chunk_value, $channel, $wg) {
            // 执行1份数据(2500/100=25个)
            $myCurlObj = new MyCurl();
            foreach ($chunk_value as $pc_value) {
                $result_curl = $myCurlObj->curl_test($chunk_key . "_" . $pc_value);
                if ($result_curl === false) {
                    MyCurl::$fail_arr[] = $pc_value;
                } else {
                    //
                    var_dump("fromWeb:" . $result_curl);
                    $channel->push($result_curl);
                }
            }
            $wg->done();
        });
    }


    // 一个协程消费数据
    go(function () use ($channel) {
        $myUseMysql=new MyUseMysql();
        while (true) {
            // 判断管道是否存在
            $data = $channel->pop();
            // var_dump($channel);
            // 判断管道是否关闭
            if ($channel->errCode === SWOOLE_CHANNEL_CLOSED) break;
            if ($channel->errCode === SWOOLE_CHANNEL_TIMEOUT) continue;
            if ($data) {
                var_dump("toMysql:" . $data);
                $myUseMysql->setMsg($data);
            }
        }
    });

    // 等待所有协程任务完成
    $wg->wait();
    //关闭管道
    $channel->close();

    // 输出失败数组
    var_dump("失败数组:");
    var_dump(MyCurl::$fail_arr);
});

返回结果报错:0 [main] swoole-cli 1802 cygwin_exception::open_stackdumpfile: Dumping stack trace to swoole-cli.exe.stackdump

然后报错的 swoole-cli.exe.stackdump的信息:


Exception: STATUS_ACCESS_VIOLATION at rip=0001008B80BA
rax=0000000100833160 rbx=0000000A0054E590 rcx=0000000000000000
rdx=0000000000000000 rsi=00000007FFFF9050 rdi=0000000000000000
r8 =0000000000000000 r9 =0000000A0012E068 r10=0000000800000000
r11=00000003FF76D542 r12=0000000000000000 r13=0000000000130000
r14=00006FFFFFE13090 r15=00006FFFFFFC0FC0
rbp=00000001015A473F rsp=00000007FFFF8F60
program=D:\swoole-cli-v4.8.13\bin\swoole-cli.exe, pid 1802, thread main
cs=0033 ds=002B es=002B fs=0053 gs=002B ss=002B
Stack trace:
Frame         Function      Args
0001015A473F  0001008B80BA (000000000000, 0001015A4710, 000000130000, 6FFFFFE13090) swoole-cli.exe+0x4B80BA
0001015A473F  0001008BE7E3 (6FFF00000003, 000A000000C7, 000100B5477A, 000A00418D90) swoole-cli.exe+0x4BE7E3
0001015A473F  0001008F5D44 (000100B67430, 6FFFFFF02390, 000000000001, 6FFFFFF02380) swoole-cli.exe+0x4F5D44
6FFFFFE8A748  00010083DE3D (000000000000, 000000000000, 000A00391D10, 6FFFFFE131E0) swoole-cli.exe+0x43DE3D
6FFFFFE8A748  0001008368B2 (0007FFFF9320, 000000000003, 000000000008, 0007FFFF9140) swoole-cli.exe+0x4368B2
000000200308  000100A37A07 (0001016FB3E0, 6FFFFFE76100, 0001009DA3D6, 000000000000) swoole-cli.exe+0x637A07
000000000000  000100A37D82 (000700000008, 0007FFFFA630, 0007FFFFB8B0, 0007FFFFCC38) swoole-cli.exe+0x637D82
0007FFFF9320  0001009CCD3B (000000000200, 000000000022, 000000000000, 0007FFFFB810) swoole-cli.exe+0x5CCD3B
0007FFFFA380  0001009686F3 (000100966A00, 000100BA4748, 0001009669F0, 000700000000) swoole-cli.exe+0x5686F3
000000000000  000100AAE58B (0007FFFFCC30, 000000000025, 0000FF52424B, 0007FFFFCA84) swoole-cli.exe+0x6AE58B
000000000000  000100BC4FB8 (0007FFFFCC30, 000000000000, 7FF9B4688035, 0007FFFFCC50) swoole-cli.exe+0x7C4FB8
0007FFFFCD30  7FF9B46880A1 (000000000000, 000000000000, 000000000000, 000000000000) cygwin1.dll+0x80A1
0007FFFFFFF0  7FF9B4685C86 (000000000000, 000000000000, 000000000000, 000000000000) cygwin1.dll+0x5C86
0007FFFFFFF0  7FF9B4685D34 (000000000000, 000000000000, 000000000000, 000000000000) cygwin1.dll+0x5D34
End of stack trace
Loaded modules:
000100400000 swoole-cli.exe
7FFA277A0000 ntdll.dll
7FFA276F0000 KERNEL32.DLL
7FFA24C80000 KERNELBASE.dll
0003F3A30000 cygMagickCore-7.Q16HDRI-7.dll
0003FFE60000 cygbrotlidec-1.dll
0003F38F0000 cygMagickWand-7.Q16HDRI-7.dll
0003F3540000 cygbrotlienc-1.dll
0003FFE40000 cygbz2-1.dll
0003F33C0000 cygcares-2.dll
0003FFB60000 cygcrypto-1.1.dll
7FFA25450000 ADVAPI32.dll
7FFA27590000 msvcrt.dll
7FFA27690000 sechost.dll
7FFA24FB0000 RPCRT4.dll
0003FFAB0000 cygcurl-4.dll
7FF9B4680000 cygwin1.dll
0003F41C0000 cygexslt-0.dll
7FFA27020000 GDI32.dll
7FFA24E60000 USER32.dll
0003F2980000 cygfreetype-6.dll
0003FF580000 cyggmp-10.dll
0003F23D0000 cygiconv-2.dll
0003F20F0000 cygicui18n72.dll
0003FF4F0000 cygicuio72.dll
0003F1F30000 cygicuuc72.dll
0003EEAE0000 cygjpeg-8.dll
0003EE7B0000 cygonig-5.dll
0003EE570000 cygpng16-16.dll
0003FE600000 cygreadline7.dll
0003F5940000 cygsqlite3-0.dll
0003FE470000 cygssl-1.1.dll
0003FDF20000 cygxml2-2.dll
0003F4180000 cygxslt-1.dll
0003EDC80000 cygyaml-0-2.dll
0003FDF00000 cygz.dll
0003ED690000 cygzip-5.dll
0003FF760000 cyggcc_s-seh-1.dll
0003FF540000 cyggomp-1.dll
0003FE290000 cygstdc++-6.dll
0003F37B0000 cygX11-6.dll
0003F3730000 cygXext-6.dll
0003FFE80000 cygbrotlicommon-1.dll
0003F3420000 cygcairo-2.dll
0003F3380000 cygcgraph-6.dll
0003F3160000 cygdjvulibre-21.dll
0003F2F20000 cygfftw3-3.dll
0003F2B80000 cygfontconfig-1.dll
0003F2AE0000 cygfpx-1.dll
0003F2590000 cygglib-2.0-0.dll
0003F2520000 cyggobject-2.0-0.dll
0003EC0E0000 cyggs-9.dll
0003F0E70000 cyggvc-6.dll
0003EEBA0000 cygjbig-2.dll
0003EEA80000 cyglcms2-2.dll
0003EEA60000 cyglqr-1-0.dll
0003FED10000 cyglzma-5.dll
0003EE700000 cygpango-1.0-0.dll
0003EE6E0000 cygpangocairo-1.0-0.dll
0003EE240000 cygraqm-0.dll
0003EE060000 cygraw_r-16.dll
0003EE020000 cygrsvg-2-2.dll
0003EDE10000 cygtiff-6.dll
0003EDD80000 cygwebp-7.dll
0003EDD30000 cygwebpdemux-2.dll
0003EDD10000 cygwebpmux-3.dll
0003FF730000 cyggsasl-18.dll
0003FF4A0000 cyggssapi_krb5-2.dll
0003FE750000 cygidn2-0.dll
0003FEF80000 cyglber-2.dll
0003FEE60000 cygldap-2.dll
0003FE710000 cygnghttp2-14.dll
0003FE6B0000 cygpsl-5.dll
0003FE500000 cygssh2-1.dll
0003FDE50000 cygzstd-1.dll
0003FF640000 cyggcrypt-20.dll
0003EA300000 cygicudata72.dll
0003FE9B0000 cygncursesw-10.dll
0003ED720000 cygcrypto-1.0.0.dll
0003EDCE0000 cygxcb-1.dll
0003EE5D0000 cygpixman-1-0.dll
0003F33A0000 cygcdt-5.dll
0003EDCC0000 cygxcb-render-0.dll
0003EDCB0000 cygxcb-shm-0.dll
0003F3670000 cygXrender-1.dll
0003FF810000 cygexpat-1.dll
0003FF2E0000 cygintl-8.dll
0003FE0A0000 cyguuid-1.dll
0003FF7A0000 cygffi-6.dll
0003FE7B0000 cygpcre-1.dll
0003F3610000 cygXt-6.dll
0003FF370000 cygidn-12.dll
0003EE680000 cygpathplan-4.dll
0003F3FE0000 cygltdl-7.dll
0003EE6A0000 cygpaper-1.dll
0003F5E50000 cygtiff-7.dll
0003EDE90000 cygthai-0.dll
0003EE6C0000 cygpangoft2-1.0-0.dll
0003F2960000 cygfribidi-0.dll
0003F5ED0000 cygharfbuzz-0.dll
0003EEBC0000 cygjasper-4.dll
0003F3330000 cygcroco-0.6-3.dll
0003F2820000 cyggdk_pixbuf-2.0-0.dll
0003F2690000 cyggio-2.0-0.dll
0003F3300000 cygdeflate-0.dll
0003FEDB0000 cygsharpyuv-0.dll
0003FE960000 cygntlm-0.dll
0003FF0D0000 cygk5crypto-3.dll
0003FF000000 cygkrb5-3.dll
0003FEFE0000 cygkrb5support-0.dll
0003FFE30000 cygcom_err-2.dll
0003FE590000 cygsasl2-3.dll
0003F1AF0000 cygunistring-5.dll
0003FF510000 cyggpg-error-0.dll
0003F37A0000 cygXau-6.dll
0003F3750000 cygXdmcp-6.dll
0003F3ED0000 cygICE-6.dll
0003F38E0000 cygSM-6.dll
0003F3320000 cygdatrie-1.dll
0003F24F0000 cyggraphite2-3.dll
0003F2580000 cyggmodule-2.0-0.dll
7FFA23B70000 CRYPTBASE.DLL
7FFA23FC0000 bcryptPrimitives.dll
7FFA256B0000 IMM32.DLL
7FFA256F0000 MSCTF.dll
7FFA23620000 VozokopotSDP.dll
7FFA250F0000 COMDLG32.dll
7FFA251D0000 combase.dll
7FFA249F0000 shcore.dll
7FFA27460000 SHLWAPI.dll
7FFA25870000 SHELL32.dll
7FFA243C0000 windows.storage.dll
7FFA24250000 kernel.appcore.dll
7FFA241E0000 powrprof.dll
7FFA241C0000 profapi.dll
7FFA23320000 COMCTL32.dll
7FFA1D0E0000 netapi32.dll
7FFA1FBE0000 wkscli.dll
7FFA230E0000 srvcli.dll
7FFA230D0000 netutils.dll
7FFA23CB0000 bcrypt.dll
7FFA20120000 SAMCLI.DLL
7FFA21AC0000 SAMLIB.dll
7FFA22F60000 authz.dll
7FFA20CA0000 iphlpapi.dll
7FFA27220000 NSI.dll
7FFA20B60000 WINNSI.DLL
7FFA237A0000 DNSAPI.dll
7FFA271B0000 WS2_32.dll
7FFA1A3F0000 MozartBreathCoreSDP.dll
7FFA272B0000 ole32.dll
7FFA274C0000 OLEAUT32.dll
00006DC00000 SteinwayMSVCRT.dll
00006DB30000 SteinwayMSVCSTL.dll
7FFA1FC30000 WINSPOOL.DRV
7FFA21AA0000 WTSAPI32.dll
7FFA23110000 MPR.dll
7FFA1B420000 wsock32.dll
7FFA1FD10000 dhcpcsvc6.DLL
7FFA19F40000 SauternesCoreSDP.dll
7FFA1FF80000 dhcpcsvc.DLL
7FFA19B90000 MozartBreathPrintSDP.dll
7FFA190A0000 MozartBreathBoloSDP.dll
7FFA250E0000 psapi.dll
7FFA1F9A0000 Wlanapi.dll
7FFA239A0000 mswsock.dll

请问是什么问题该如何使得在消费协程中 可以把数据插到数据库

@NathanFreeman
Copy link
Member

你试试高版本的swoole-cli会不会出现这个问题

@jakepaulcnias123
Copy link

jakepaulcnias123 commented May 20, 2024

出现这个错误的原因可能有很多,包括代码中的并发处理、Cygwin环境的兼容性问题或其他潜在的代码错误。这里有一些建议和调试步骤,可以帮助你解决这个问题:

  1. 确认Cygwin环境
    确保你使用的是最新版本的Cygwin,并且所有相关的库和工具都已更新到最新版本。由于Swoole是在Linux上开发和优化的,可能会出现与Windows/Cygwin兼容性的问题。

  2. 检查并发处理
    并发处理是造成问题的常见原因,尤其是在处理大量数据时。你可以尝试减少并发量,以确认是否是由于并发引起的错误。

  3. 增加错误处理和日志记录
    在代码中添加更多的错误处理和日志记录,以便更好地了解在哪一步出现了错误。例如,在数据库操作和Curl操作中增加更多的错误检查和日志记录。

  4. 逐步测试
    逐步测试每个部分,以便确定问题的根源。先测试Curl操作,然后测试数据库插入操作,最后再将两者结合起来。

调试示例
以下是改进后的代码示例,增加了一些错误处理和日志记录:

php
Copiază codul

connect([ 'host' => '127.0.0.1', 'port' => 3306, 'user' => 'root', 'password' => 'root', 'database' => 'test', ]); if ($res === false) { echo "MySQL connection error: " . $swoole_mysql->connect_error . "\n"; } self::$conn = $swoole_mysql; } } public function setMsg($msg) { $sql = "INSERT INTO `cache` (`msg`) VALUES ('$msg');"; $res = self::$conn->query($sql); if ($res === false) { echo "MySQL query error: " . self::$conn->error . "\n"; } } } run(function () { // 创建管道 $channel = new Channel(1); // 协程数量 $go_count = 100; // 模拟数据 $pc_arr = []; for ($pc = 1; $pc <= 250; $pc++) { $pc_arr[] = $pc; } // 分成100份模拟数据(100个协程) $chunks = array_chunk($pc_arr, ceil(count($pc_arr) / $go_count)); // 等待协程 $wg = new WaitGroup(); // 100个协程生产数据 foreach ($chunks as $chunk_key => $chunk_value) { $wg->add(); go(function () use ($chunk_key, $chunk_value, $channel, $wg) { // 执行1份数据(250/100=25个) $myCurlObj = new MyCurl(); foreach ($chunk_value as $pc_value) { $result_curl = $myCurlObj->curl_test($chunk_key . "_" . $pc_value); if ($result_curl === false) { MyCurl::$fail_arr[] = $pc_value; } else { var_dump("fromWeb:" . $result_curl); $channel->push($result_curl); } } $wg->done(); }); } // 一个协程消费数据 go(function () use ($channel) { $myUseMysql = new MyUseMysql(); while (true) { $data = $channel->pop(); if ($channel->errCode === SWOOLE_CHANNEL_CLOSED) break; if ($channel->errCode === SWOOLE_CHANNEL_TIMEOUT) continue; if ($data) { var_dump("toMysql:" . $data); $myUseMysql->setMsg($data); } } }); // 等待所有协程任务完成 $wg->wait(); // 关闭管道 $channel->close(); // 输出失败数组 var_dump("失败数组:"); var_dump(MyCurl::$fail_arr); }); 其他建议 调试工具:使用调试工具如GDB来分析崩溃的具体原因。 环境迁移:考虑迁移到Linux环境中测试和运行你的Swoole程序,Swoole在Linux上有更好的支持和表现。 Cygwin更新:确保Cygwin和所有相关库都是最新版本,并且配置正确。 通过以上方法,你应该能够更好地定位和解决问题。如果问题依然存在,考虑在Swoole的GitHub或相关社区中寻求帮助。windows 11 pro key 4 euro [https://royalcdkeys.com/products/windows-11-pro-retail-cd-key](url)

@Dadiaojin
Copy link
Author

你试试高版本的swoole-cli会不会出现这个问题

swoole-cli-v5.0.3 一样有这个问题

@Dadiaojin
Copy link
Author

我发现在上面代码的基础上加\Swoole\Coroutine::sleep(0.1); 就没有报错
全部代码如下:

<?php


use function Swoole\Coroutine\run;
use function Swoole\Coroutine\go;
use Swoole\Coroutine\Channel;
use Swoole\Coroutine\WaitGroup;


class MyCurl
{
    public static $fail_arr = [];

    public function curl_test($set)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1?set=' . $set);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $result = curl_exec($ch);
        // var_dump(curl_getinfo($ch));
        // var_dump(curl_error($ch));
        curl_close($ch);
        return $result;
    }
}

class MyUseMysql
{
    public static $instert_arr = [];
    private static $conn;

    public function __construct()
    {
        if (empty(self::$conn)) {
            $swoole_mysql = new Swoole\Coroutine\MySQL();
            $swoole_mysql->connect([
                'host' => '127.0.0.1',
                'port' => 3306,
                'user' => 'root',
                'password' => 'root',
                'database' => 'test',
            ]);
            self::$conn = $swoole_mysql;
        }
    }

    public function setMsg($msg)
    {
        $sql = "INSERT INTO `cache` (`msg`) VALUES ('$msg');";
        self::$conn->begin();
        self::$conn->query($sql);
        self::$conn->commit();
    }
}


run(function () {

    // 创建管道
    $channel = new Channel(1);

    // 协程数量
    $go_count = 100;

    // 模拟数据
    $pc_arr = [];
    for ($pc = 1; $pc <= 250; $pc++) {
        $pc_arr[] = $pc;
    }
    // 分成100份模拟数据(100个协程)
    $chunks = array_chunk($pc_arr, ceil(count($pc_arr) / $go_count));

    //等待协程
    $wg = new WaitGroup();
    // 100个协程生产数据
    foreach ($chunks as $chunk_key => $chunk_value) {
        $wg->add();
        go(function () use ($chunk_key, $chunk_value, $channel, $wg) {
            // 执行1份数据(2500/100=25个)
            $myCurlObj = new MyCurl();
            foreach ($chunk_value as $pc_value) {
                $result_curl = $myCurlObj->curl_test($chunk_key . "_" . $pc_value);
                if ($result_curl === false) {
                    MyCurl::$fail_arr[] = $pc_value;
                } else {
                    //
                    var_dump("fromWeb:" . $result_curl);
                    $channel->push($result_curl);
                }
            }
            $wg->done();
        });
    }


    // 一个协程消费数据
    go(function () use ($channel) {
        $myUseMysql=new MyUseMysql();
        while (true) {
            // 判断管道是否存在
            $data = $channel->pop();
            // var_dump($channel);
            // 判断管道是否关闭
            if ($channel->errCode === SWOOLE_CHANNEL_CLOSED) break;
            if ($channel->errCode === SWOOLE_CHANNEL_TIMEOUT) continue;
            if ($data) {
               \Swoole\Coroutine::sleep(0.1); 
                var_dump("toMysql:" . $data);
                $myUseMysql->setMsg($data);
            }
        }
    });

    // 等待所有协程任务完成
    $wg->wait();
    //关闭管道
    $channel->close();

    // 输出失败数组
    var_dump("失败数组:");
    var_dump(MyCurl::$fail_arr);
});

究竟是为什么?

@NathanFreeman
Copy link
Member

把协程数量$go_count = 500;调整大一点,cygwin还是没法很好的模拟linux环境。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants