Deprecated
: htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated in
/www/wwwroot/testblog.58heshihu.com/var/Widget/Archive.php
on line
1057
首页
关于
Search
1
给你10个市场数据调研报告的免费下载网站!以后竞品数据就从这里找!
182 阅读
2
php接口优化 使用curl_multi_init批量请求
144 阅读
3
《从菜鸟到大师之路 ElasticSearch 篇》
107 阅读
4
2024年备考系统架构设计师
104 阅读
5
PHP 文件I/O
92 阅读
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
登录
Search
标签搜索
php函数
php语法
性能优化
安全
错误和异常处理
问题
vue
Composer
Session
缓存
框架
Swoole
api
并发
异步
正则表达式
php-fpm
mysql 索引
开发规范
协程
dafenqi
累计撰写
786
篇文章
累计收到
28
条评论
首页
栏目
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
副业
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
页面
关于
搜索到
7
篇与
的结果
2024-01-02
PHP中如何处理多线程错误?
PHP中如何处理多线程错误?多线程编程是一种高效的编程模式,可以提高程序的并发能力和响应速度。在PHP中,虽然没有官方支持的多线程库,但我们可以使用第三方扩展库来实现多线程。然而,在多线程编程中,错误处理是一个非常重要的问题。本文将介绍在PHP中如何处理多线程错误,并提供具体的代码示例。首先,我们需要使用pthreads扩展库来实现多线程。可以通过以下步骤来安装pthreads扩展:1.下载pthreads扩展库的源码,可以从GitHub上找到最新版本。2.解压源码并进入解压后的目录。3.在终端中运行以下命令进行编译和安装:$ phpize $ ./configure $ make $ make install安装完成后,在php.ini文件中添加以下行:extension=pthreads.so重启PHP服务器使扩展生效。接下来,我们将介绍在多线程编程中如何处理错误。一、使用try-catch块捕获异常在多线程环境中抛出的异常无法直接传递给主线程,因此我们需要在子线程中捕获异常,并将异常信息传递给主线程进行处理。示例代码如下:class MyThread extends Thread { public function run() { try { // 线程执行的代码 // 可能会抛出异常 } catch (Throwable $e) { // 将异常信息传递给主线程 $this->setThrowable($e); } } } $thread = new MyThread(); $thread->start(); $thread->join(); // 在主线程中处理异常 if ($thread->isJoined() && $thread->getThrowable()) { $exception = $thread->getThrowable(); // 处理异常 // 输出异常信息或进行其他操作 }通过将异常信息传递给主线程,在主线程中可以对异常进行处理,例如输出异常信息或进行其他操作。二、使用全局变量或共享内存传递错误信息另一种处理多线程错误的方法是使用全局变量或共享内存传递错误信息。示例代码如下:class MyThread extends Thread { private $error; public function run() { // 线程执行的代码 // 可能会发生错误 if ($errorOccured) { $this->error = "Something went wrong."; } } public function getError() { return $this->error; } } $thread = new MyThread(); $thread->start(); $thread->join(); // 在主线程中处理错误 if ($thread->isJoined() && $thread->getError()) { $error = $thread->getError(); // 处理错误 // 输出错误信息或进行其他操作 }在示例代码中,子线程发生错误时将错误信息存储在$error变量中,主线程通过调用getError方法获取错误信息进行处理。三、使用日志记录错误信息除了以上两种方法,我们还可以将错误信息记录到日志文件中。示例代码如下:class MyThread extends Thread { public function run() { // 线程执行的代码 // 可能会发生错误 if ($errorOccured) { $errorMessage = "Something went wrong."; file_put_contents("error.log", $errorMessage, FILE_APPEND); } } } $thread = new MyThread(); $thread->start(); $thread->join();在示例代码中,当子线程发生错误时,将错误信息追加到error.log文件中。在实际应用中,我们可以根据具体的需求选择合适的错误处理方式。通过以上几种方法,我们可以对多线程编程中的错误进行有效的处理和管理,在保证程序稳定性和可靠性的同时提高开发效率。
2024年01月02日
6 阅读
0 评论
0 点赞
2023-08-12
异步 PHP — 多进程、多线程和协程
异步 PHP — 多进程、多线程和协程让我们看一下这段典型的 PHP 代码:function names(){$data = Http::get('data.location/products')->json(); $names = []; foreach ($data as $item){ $names[] = $item['name']; } return $names;}我们发送一个返回项目数组的 HTTP 请求,然后我们将每个项目的名称存储在一个$names数组中。执行此函数所花费的时间等于请求的持续时间加上构建数组所花费的时间。如果我们想为不同的数据源多次运行这个函数怎么办:$products = names('/products');$users = names('/users');运行此代码所花费的时间等于两个函数组合的持续时间:HTTP request to collect products: 1.5 secondsBuilding products names array: 0.01 secondsHTTP request to collect users: 3.0 secondsBuilding users names array: 0.01 secondsTotal: 4.52 seconds图片这称为同步代码执行,或一次执行一件事。为了使此代码运行得更快,您可能希望异步执行它。那么,如果我们想实现这一目标,我们有哪些选择呢?在不同的进程中执行。在不同的线程中执行。在协程/纤维/绿色线程中执行。在不同的进程中执行在单独的进程中运行这些函数调用中的每一个,都会为操作系统提供并行运行它们的任务。如果您有一个多核处理器,我们现在都有,并且周围有 2 个空闲内核,操作系统将使用两个内核并行(同时)执行进程。但是,在大多数情况下,机器上运行的其他进程需要使用可用的内核。在这种情况下,操作系统将在这些进程之间共享 CPU 时间。换句话说,可用内核将在处理我们的两个进程和其他进程之间切换。在这种情况下,我们的进程将同时执行。这两个进程的执行时间大约是 3.03 秒(我知道不是 100% 准确)。这个结论是基于这样一个事实:最慢的请求需要 3 秒,2 次网络调用需要 10 毫秒,两个用于收集名称的循环各需要 10 毫秒。核心内部的执行将如下所示:Switch to process 1Start HTTP request to collect productsSwitch to process 2Start HTTP request to collect usersSwitch to process 1If a response came, then build products names arraySwitch to process 2If a response came, then build users names array因此,当 CPU 等待第一个请求的响应时,它会发送第二个请求。然后等到任何请求返回,然后再继续该过程。多处理是在 PHP 中实现异步代码执行的一种简单方法。但是,它并不是性能最高的。因为创建进程相对昂贵,并且每个进程都需要在内存中拥有自己的私有空间。进程之间的切换(上下文切换)也有开销。您可以使用 Laravel 队列并启动固定数量的工作人员(进程)并让它们保持活动状态以处理您的任务。这样你就不必每次想要异步运行时都创建新进程。但是,上下文切换和内存分配的开销仍将适用。同样对于工作人员,您需要管理如何从工作人员内部的代码执行中接收结果。多处理和 Laravel 工作人员已经为数百万个应用程序做得很好。因此,当我说它不是相对于其他选项时性能最好的。不要只是阅读本文并认为多处理和队列不好。好?在不同的线程中执行一个进程在内存中有自己的私有空间,一个进程可能有多个线程。所有线程都与进程位于相同的内存空间中。这使得生成线程比生成进程更便宜。但是,上下文切换仍然会发生。当你有太多线程时,比如有太多进程,你机器上的一切都会变慢。因为 CPU 内核在很多上下文之间切换。此外,由于多个线程同时访问相同的内存空间,可能会发生争用情况。除此之外,不再支持PHP 中的多线程。在 coroutines/fibers/green-threads 中执行这个“东西”有很多名字。但是我们称它为“协程”,因为它是最常用的术语。协程就像一个线程,它共享它在内部创建的进程的内存,但它不是一个实际的线程,因为操作系统对此一无所知。操作系统级别的协程之间没有上下文切换。运行时控制切换发生的时间,这比 OS 上下文切换成本更低。让我们将代码转换为使用协程。此代码仅用于演示,如果您运行它将不起作用:$products = [];$users = [];go(fn() => $products = names('/products'));go(fn() => $users = names('/users'));协程背后的想法是运行时将安排同时运行这些回调。在每个协程内部,代码可以显式地将控制权交给运行时,以便它可以运行另一个协程。在任何给定时间,只有一个协程正在执行。所以如果我们分解我们的代码,它会是这样的:go(function(){$data = Http::get('data.location/products')->json(); // yields foreach(...)});go(function(){$data = Http::get('data.location/users')->json(); // yields foreach(...)});运行时将执行第一个协程直到它产生,然后执行第二个协程直到它产生,然后返回到它在第一个协程中停止的位置。直到所有协程都执行完毕。然后,它将以常规同步方式继续执行代码。现在你可能有两个问题;首先,什么时候应该屈服?第二,我们如何实现它?在我们的示例中,每个协程内部都有两个操作;一个 I/O 绑定和一个 CPU 绑定。发送 HTTP 请求是一个 I\O 绑定操作,我们发送请求(输入)并等待响应(输出)。另一方面,循环是一个 CPU 密集型操作,我们正在循环一组记录并计算结果。计算是由 CPU 完成的,这就是为什么它被称为 CPU bound。如果在同一进程中运行,受 CPU 限制的工作将花费相同的时间。使工作花费更少时间的唯一方法是在不同的进程或线程中执行它。另一方面,I\O 绑定的工作可以在同一个进程内并发运行;当一个 I\O 操作正在等待输出时,另一个操作可以开始。查看我们的示例,运行时内部的执行将如下所示:Start coroutine 1Start HTTP request to collect productsCoroutine 1 yieldsSwitch to coroutine 2Start HTTP request to collect usersCoroutine 2 yieldsSwitch to coroutine 1If a response came, then build products names arraySwitch to coroutine 2If a response came, then build users names array使用协程,我们可以将 I\O 操作花费在等待上的时间用于做其他工作。通过这样做,我们同时运行所有协程。现在让我们转向我们的第二个问题:我们如何使屈服发生?我们没有。不同的框架和库必须通过在 I\O 操作等待时让出控制来支持异步执行。有一个流行的术语,你应该知道“非阻塞 I\O”。与数据库、缓存、文件系统、网络等通信的库必须适应非阻塞。如果您在协程中使用阻塞库,它将永远不会产生,因此您的协程将同步执行。主进程将等到 I\O 操作收到输出,然后再继续程序的其余部分。结论关于协程和异步执行还有很多话要说。我的计划是探索如何让 Laravel 与协程很好地配合,并在此过程中分享我的发现。在那之前,拥抱 PHP 的同步代码执行。超过 25 年,它运行良好。将您需要剪切的 I\O 绑定工作发送到队列工作程序并稍后对结果采取行动。这应该涵盖许多用例。
2023年08月12日
16 阅读
0 评论
0 点赞
2023-08-08
PHP 高级编程之多线程
PHP 高级编程之多线程
2023年08月08日
13 阅读
0 评论
0 点赞
2023-08-08
PHP并行 多进程/多线程
PHP并行 多进程/多线程PHP中提供了一个扩展pcntl,可以利用操作系统的fork调用来实现多进程。fork调用后执行的代码将是并行的。注:pcntl仅支持linux平台,并且只能在cli模式下使用。$pid = pcntl_fork(); if($pid > 0){ //父进程代码 exit(0); } elseif($pid == 0) { //子进程代码 exit(0); }PHP官方没有提供多线程的扩展,pecl中有一个pthreads扩展提供了多线程的特性,地址是http://pecl.php.net/package/pthreads,此扩展仅在线程安全版本中可用。多进程和多线程其实是作用是相同的。区别是线程是在同一个进程内的,可以共享内存变量实现线程间通信线程比进程更轻量级,开很大量进程会比线程消耗更多系统资源多线程也存在一些问题:线程读写变量存在同步问题,需要加锁锁的粒度过大会有性能问题,可能会导致只有1个线程在运行,其他线程都在等待锁。这样就不是并行了同时使用多个锁,逻辑复杂,一旦某个锁没被正确释放,可能会发生线程死锁某个线程发生致命错误会导致整个进程崩溃多进程方式更加稳定,另外利用进程间通信(IPC)也可以实现数据共享。共享内存,这种方式和线程间读写变量是一样的,需要加锁,会有同步、死锁问题。消息队列,可以采用多个子进程抢队列模式,性能很好PIPE,UnixSock,TCP,UDP。可以使用read/write来传递数据,TCP/UDP方式使用socket来通信,子进程可以分布运行利用fork可以实现一个最简单的并发TCP Server。主进程accept连接,有新的连接到来就Fork一个子进程。子进程中循环recv/send,处理数据。这种模式在请求量不多情况下很实用,像FTP服务器。过去有很多Linux程序都是这种模式的,简单高效,几十行代码就可以实现。当然这种模型在几百个并发的情况下还算不错,大量并发的情况下就有点消耗过大了。if(($sock = socket_create(AF_INET, SOCK_STREAM, 0)) < 0) { echo "failed to create socket: ".socket_strerror($sock)."\n"; exit(); } if(($ret = socket_bind($sock, $address, $port)) < 0) { echo "failed to bind socket: ".socket_strerror($ret)."\n"; exit(); } if( ( $ret = socket_listen( $sock, 0 ) ) < 0 ) { echo "failed to listen to socket: ".socket_strerror($ret)."\n"; exit(); } while (true) { $conn = @socket_accept($sock); //子进程 if(pcntl_fork() == 0) { $recv = socket_read($conn, 8192); //处理数据 $send_data = "server: ".$recv; socket_write($conn, $send_data); socket_close($conn); exit(0); } else { socket_close($conn); } }
2023年08月08日
16 阅读
0 评论
0 点赞
2023-08-08
PHP实现多线程抓取网页
PHP实现多线程抓取网页PHP 利用 Curl Functions 可以完成各种传送文件操作,比如模拟浏览器发送GET,POST请求等等,受限于php语言本身不支持多线程,所以开发爬虫程序效率并不高,这时候往往需 要借助Curl Multi Functions 它可以实现并发多线程的访问多个url地址。既然 Curl Multi Function如此强大,能否用 Curl Multi Functions 来写 并发多线程下载文件 呢,当然可以,下面给出我的代码:代码1:将获得的代码直接写入某个文件<?php $urls = array( 'http://www.sina.com.cn/', 'http://www.sohu.com/', 'http://www.163.com/' ); // 设置要抓取的页面URL $save_to='/test.txt'; // 把抓取的代码写入该文件 $st = fopen($save_to,"a"); $mh = curl_multi_init(); foreach ($urls as $i => $url) { $conn[$i] = curl_init($url); curl_setopt($conn[$i], CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)"); curl_setopt($conn[$i], CURLOPT_HEADER ,0); curl_setopt($conn[$i], CURLOPT_CONNECTTIMEOUT,60); curl_setopt($conn[$i], CURLOPT_FILE,$st); // 设置将爬取的代码写入文件 curl_multi_add_handle ($mh,$conn[$i]); } // 初始化 do { curl_multi_exec($mh,$active); } while ($active); // 执行 foreach ($urls as $i => $url) { curl_multi_remove_handle($mh,$conn[$i]); curl_close($conn[$i]); } // 结束清理 curl_multi_close($mh); fclose($st); ?>代码2:将获得的代码先放入变量,再写入某个文件<?php $urls = array( 'http://www.sina.com.cn/', 'http://www.sohu.com/', 'http://www.163.com/' ); $save_to='/test.txt'; // 把抓取的代码写入该文件 $st = fopen($save_to,"a"); $mh = curl_multi_init(); foreach ($urls as $i => $url) { $conn[$i] = curl_init($url); curl_setopt($conn[$i], CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)"); curl_setopt($conn[$i], CURLOPT_HEADER ,0); curl_setopt($conn[$i], CURLOPT_CONNECTTIMEOUT,60); curl_setopt($conn[$i],CURLOPT_RETURNTRANSFER,true); // 设置不将爬取代码写到浏览器,而是转化为字符串 curl_multi_add_handle ($mh,$conn[$i]); } do { curl_multi_exec($mh,$active); } while ($active); foreach ($urls as $i => $url) { $data = curl_multi_getcontent($conn[$i]); // 获得爬取的代码字符串 fwrite($st,$data); // 将字符串写入文件。当然,也可以不写入文件,比如存入数据库 } // 获得数据变量,并写入文件 foreach ($urls as $i => $url) { curl_multi_remove_handle($mh,$conn[$i]); curl_close($conn[$i]); } curl_multi_close($mh); fclose($st); ?>
2023年08月08日
13 阅读
0 评论
0 点赞
1
2