<!–
* {
color:#3e3e3e;
}
body {
font-family: “Helvetica Neue”,Helvetica,”Hiragino Sans GB”,”Microsoft YaHei”,Arial,sans-serif;
font-size: 15px;
}
p{
line-height: 25.6px ;
box-sizing: border-box;
word-wrap: break-word;
text-align: justify;
margin: 23.7px 0;
}
blockquote {
border-left: 2px solid rgba(128,128,128,0.075);
background-color: rgba(128,128,128,0.05);
padding: 10px -1px;
margin: 0px;
}
blockquote p {
color: #898989;
margin: 0px;
}
strong {
font-weight: 700;
color: #3e3e3e;
}
pre {
background-color: #f8f8f8;
border-radius: 3px;
word-wrap: break-word;
overflow: scroll;
padding: 12px 13px;
font-size: 13px;
color: #898989;
}
h1,h2,h3,h4,h5,h6 {
word-break: break-all;
text-align: left;
font-weight: bold;
}
hr{border:1px solid #ddd;}
h1{font-size:170%;ng-top:.5em;margin-topborder-top:4px solid #aaa;paddi:1.5em;}
h1:first-child{margin-top:0;padding-top:.25em;border-top:none;}
table {
padding: 0;border-collapse: collapse; }
table tr {
border-top: 1px solid #cccccc;
background-color: white;
margin: 0;
padding: 0; }
table tr:nth-child(2n) {
background-color: #f8f8f8; }
table tr th {
font-weight: bold;
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
table tr td {
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
table tr th :first-child, table tr td :first-child {
margin-top: 0; }
table tr th :last-child, table tr td :last-child {
margin-bottom: 0; }
a {
color: #4183C4;
text-decoration: none;
}
ul, ol {
padding-left: 30px;
}
li {
line-height: 24px;
}
hr {
height: 2px;
padding: 0;
margin: 16px 0;
background-color: #e7e7e7;
border: 0 none;
overflow: hidden;
box-sizing: content-box;
border-bottom: 1px solid #ddd;
}
pre {
background: #f2f2f2;
padding: 12px 13px;
}
code {
padding:2px 4px;
color: #c7254e;
background: #f9f2f4;
border-radius:4px;
}
code[class*=”language-“],
pre[class*=”language-“] {
color: black;
background: none;
font-family: Consolas, Monaco, ‘Andale Mono’, ‘Ubuntu Mono’, monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*=”language-“] {
position: relative;
margin: .5em 0;
-webkit-box-shadow: -1px 0px 0px 0px #358ccb, 0px 0px 0px 1px #dfdfdf;
-moz-box-shadow: -1px 0px 0px 0px #358ccb, 0px 0px 0px 1px #dfdfdf;
box-shadow: -1px 0px 0px 0px #358ccb, 0px 0px 0px 1px #dfdfdf;
border-left: 10px solid #358ccb;
background-color: #fdfdfd;
background-image: -webkit-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
background-image: -moz-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
background-image: -ms-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
background-image: -o-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
background-image: linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
background-size: 3em 3em;
background-origin: content-box;
overflow: visible;
padding: 0;
}
code[class*=”language”] {
max-height: inherit;
height: 100%;
padding: 0 1em;
display: block;
overflow: auto;
}
:not(pre) >–> code[class*=”language-“],
pre[class*=”language-“] {
background-color: #fdfdfd;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
margin-bottom: 1em;
}
:not(pre) > code[class*=”language-“] {
position: relative;
padding: .2em;
-webkit-border-radius: 0.3em;
-moz-border-radius: 0.3em;
-ms-border-radius: 0.3em;
-o-border-radius: 0.3em;
border-radius: 0.3em;
color: #c92c2c;
border: 1px solid rgba(0, 0, 0, 0.1);
display: inline;
white-space: normal;
}
pre[class*=”language-“]:before,
pre[class*=”language-“]:after {
content: ”;
z-index: -2;
display: block;
position: absolute;
bottom: 0.75em;
left: 0.18em;
width: 40%;
height: 20%;
max-height: 13em;
-webkit-box-shadow: 0px 13px 8px #979797;
-moz-box-shadow: 0px 13px 8px #979797;
box-shadow: 0px 13px 8px #979797;
-webkit-transform: rotate(-2deg);
-moz-transform: rotate(-2deg);
-ms-transform: rotate(-2deg);
-o-transform: rotate(-2deg);
transform: rotate(-2deg);
}
:not(pre) > code[class*=”language-“]:after,
pre[class*=”language-“]:after {
right: 0.75em;
left: auto;
-webkit-transform: rotate(2deg);
-moz-transform: rotate(2deg);
-ms-transform: rotate(2deg);
-o-transform: rotate(2deg);
transform: rotate(2deg);
}
.token.comment,
.token.block-comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #7D8B99;
}
.token.punctuation {
color: #5F6364;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.function-name,
.token.constant,
.token.symbol,
.token.deleted {
color: #c92c2c;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.function,
.token.builtin,
.token.inserted {
color: #2f9c0a;
}
.token.operator,
.token.entity,
.token.url,
.token.variable {
color: #a67f59;
background: rgba(255, 255, 255, 0.5);
}
.token.atrule,
.token.attr-value,
.token.keyword,
.token.class-name {
color: #1990b8;
}
.token.regex,
.token.important {
color: #e90;
}
.language-css .token.string,
.style .token.string {
color: #a67f59;
background: rgba(255, 255, 255, 0.5);
}
.token.important {
font-weight: normal;
}
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
.namespace {
opacity: .7;
}
@media screen and (max-width: 767px) {
pre[class*=”language-“]:before,
pre[class*=”language-“]:after {
bottom: 14px;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
}
.token.tab:not(:empty):before,
.token.cr:before,
.token.lf:before {
color: #e0d7d1;
}
pre[class*=”language-“].line-numbers {
padding-left: 0;
}
pre[class*=”language-“].line-numbers code {
padding-left: 3.8em;
}
pre[class*=”language-“].line-numbers .line-numbers-rows {
left: 0;
}
pre[class*=”language-“][data-line] {
padding-top: 0;
padding-bottom: 0;
padding-left: 0;
}
pre[data-line] code {
position: relative;
padding-left: 4em;
}
pre .line-highlight {
margin-top: 0;
}
pre.line-numbers {
position: relative;
padding-left: 3.8em;
counter-reset: linenumber;
}
pre.line-numbers > code {
position: relative;
}
.line-numbers .line-numbers-rows {
position: absolute;
pointer-events: none;
top: 0;
font-size: 100%;
left: -3.8em;
width: 3em; /* works for line-numbers below 1000 lines */
letter-spacing: -1px;
border-right: 1px solid #999;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.line-numbers-rows > span {
pointer-events: none;
display: block;
counter-increment: linenumber;
}
.line-numbers-rows > span:before {
content: counter(linenumber);
color: #999;
display: block;
padding-right: 0.8em;
text-align: right;
}
–>
前言
前些天帮同事查一个问题,第一次接触到了 PHP 的多线程,原以为 PHP 普遍都是单线程模型,并不适合多线程领域,花些时间翻了几个多线程的项目源码之后,发现 PHP 的多线程也颇有可取之处,活用起来,用来解决某些问题竟然非常适合。
于是找了几篇文章看了下 PHP 多线程 TSRM
机制的实现,也有所收获,详情可以查看下面的参考文章。本文对比多进程介绍了下多线程的优势和适用场景,提出了一种巧用方案,并使用 PHP 代码实现了多线程的常见用法。
文章欢迎转载,但请注明来源:http://www.cnblogs.com/zhenbianshu/p/7978835.html, 谢谢。
多线程
线程
首先说下线程:
线程(thread) 是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务.
使用多线程主要是因为它在执行效率上有很大优势。由于线程是操作系统能够进行调度的最小单位
:
- 一个多线程程序比单线程程序被操作系统调度的概率更大,所以多线程程序一般会比单线程程序更高效;
- 多线程程序的多个线程可以在多核 CPU 的多个核心同时运行,可以将完全发挥机器多核的优势;
同时对比多进程程序,多线程有以下特点:
- 线程的创建和切换的系统开销都比进程要小,所以一定程度上会比多进程更高效;
- 线程天生的共享内存空间,线程间的通信更简单,避免了进程IPC引入新的复杂度。
适用场景
多线程的优化是很多,可是无脑使用多线程并不能提升程序的执行效率,因为线程的创建和销毁、上下文切换、线程同步等也是有性能损耗的,耗费时间可能比顺序执行的代码还多。如:
sumSmall
是一个从1累加到50000的函数。
上图是在主线程内执行了三次 sumSmall 和三个线程分别执行 sumSmall ,再将结果同步到一个线程的时间对比,我们会发现只在主线程执行的时间反而更短,三个线程创建、切换、同步的时间远远大过了线程异步执行节省的时间。
而函数 sumLarge 从1累加到5000000,下图同一线程执行三次和三个线程执行的耗时:
这次,多线程终于有效率优势了。
是否使用多线程还需要根据具体需求而定,一般考虑以下两种情况:
- I/O 阻塞会使操作系统发生任务调度,阻塞当前任务,所以代码中 I/O 多的情况下,使用多线程时可以将代码并行。例如多次读整块的文件,或请求多个网络资源。
- 多线程能充分利用 CPU,所以有多处大计算量代码时,也可以使用多线程使他们并行执行,例如上文中后一个例子。
PHP中的多线程
PHP 默认并不支持多线程,要使用多线程需要安装 pthread 扩展,而要安装 pthread 扩展,必须使用 --enable-maintainer-zts
参数重新编译 PHP,这个参数是指定编译 PHP 时使用线程安全方式。
线程安全
多线程是让程序变得不安分的一个因素,在使用多线程之前,首先要考虑线程安全问题:
线程安全:线程安全是编程中的术语,指某个函数、函数库在多线程环境中被调用时,能够正确地处理多个线程之间的共享变量,使程序功能正确完成。
在传统多线程中,由于多个线程共享变量,所以可能会导致出现如下问题:
- 存在一个全局数组
$arr = array('a');
; - A 线程获取数组长度为1;
- B 线程获取数组长度为1;
- A 线程 pop 出数组元素
$a = array_pop($arr); $a = 'a';
; - B 线程也 pop 数组元素
$b = array_pop($arr); $a = null;
; - 此时 B 线程内就出现了灵异事件,明明数组长度大于0,或没有 pop 出东西;
PHP 实现
PHP 实现的线程安全主要是使用 TSRM
机制对 全局变量和静态变量进行了隔离
,将全局变量和静态变量 给每个线程都复制了一份,各线程使用的都是主线程的一个备份,从而避免了变量冲突,也就不会出现线程安全问题。
PHP 对多线程的封装保证了线程安全,程序员不用考虑对全局变量加各种锁来避免读写冲突了,同时也减少了出错的机会,写出的代码更加安全。
但由此导致的是,子线程一旦开始运行,主线程便无法再对子线程运行细节进行调整了,线程一定程度上失去了线程之间通过全局变量进行消息传递的能力。
同时 PHP 开启线程安全选项后,使用 TSRM
机制分配和使用变量时也会有额外的损耗,所以在不需要多线程的 PHP 环境中,使用 PHP 的 ZTS (非线程安全) 版本就好。
类和方法
PHP 将线程 封装成了 Thread
类,线程的创建通过实例化一个线程对象来实现,由于类的封装性,变量的使用只能通过构造函数传入,而线程运算结果也需要通过类变量传出。
下面介绍几个常用的 Thread 类方法:
run()
:此方法是一个抽象方法,每个线程都要实现此方法,线程开始运行后,此方法中的代码会自动执行;start()
:在主线程内调用此方法以开始运行一个线程;join()
:各个线程相对于主线程都是异步执行,调用此方法会等待线程执行结束;kill()
:强制线程结束;isRunning()
:返回线程的运行状态,线程正在执行run()
方法的代码时会返回 true;
因为线程安全的实现,PHP 的多线程开始运行后,无法再通过共享内存空间通信,线程也无法通过线程间通信复用,所以我认为 PHP 的“线程池”并没有什么意义。扩展内自带的Pool
类是一个对多线程分配管理的类,这里也不再多介绍了。
实例代码
下面是一个线程类,用来请求某一接口。接下来根据它写两个多线程的应用实例:
class Request extends Thread {
public $url;
public $response;
public function __construct($url) {
$this->url = $url;
}
public function run() {
$this->response = file_get_contents($this->url);
}
}
异步请求
将同步的请求拆分为多个线程异步调用,以提升程序的运行效率。
$chG = new Request("www.google.com");
$chB = new Request("www.baidu.com");
$chG ->start();
$chB ->start();
$chG->join();
$chB->join();$gl = $chG->response;
$bd = $chB->response;
超时控制
偶然间发现公司网站某一网页上的一块内容时有时无,不知道具体实现,但这给了我使用多线程的灵感:利用线程异步实现快速失败和超时控制。
我们在使用 curl 请求某个地址时,可以通过 CURLOPT_CONNECTTIMEOUT / CURLOPT_TIMEOUT
参数分别设置 curl 的连接超时时间和读取数据超时时间,但总的超时时间不好控制。而且在进行数据库查询时的超时时间无法设置(鸟哥博客:为MySQL设置查询超时)。
这时我们便可以借用多线程来实现此功能:在执行线程类的 start()
方法后,不调用 join()
方法,使线程一直处于异步状态,不阻塞主线程的执行。
此时主线程相当于旗舰,而各子线程相当于巡航舰,旗舰到达某地后不必要一直等待巡航舰也归来,等待一段时间后离开即可,从而避免巡航舰意外时旗舰白白空等。
代码:
$chG = new Request("www.google.com");
$chB = new Request("www.baidu.com");
$chG->start();
$chB->start();
$chB->join();
// 此处不对chG执行join方法sleep(1); // sleep一个能接受的超时时间
$gl = $chG->response;
$bd = $chB->response;
$bd->kill();
if (!$gl) {
$gl = ""; // 处理异常,或在线程类内给$gl一个默认值
}
总结
PHP 对多线程进行的封(yan)装(ge),让人用线程用得非常不尽兴。虽然安全,也保持 PHP 简单易用的一贯风格,却无法完全发挥多线程的能力。不过各个语言各有特色和侧重点,也不必强求,爱她就要包容她 =_=。
最近在重学操作系统和 Linux 内核方面的知识,对程序的认知有了很大提升,感觉非常有必要总结一下,敬请期待。
关于本文有什么问题可以在下面留言交流,如果您觉得本文对您有帮助,可以点击下面的 推荐
支持一下我,博客一直在更新,欢迎 关注
。
参考: