云服务器

PHP代码优化与性能提升:多线程

2019-12-05 11:09:40 95

对于c++,java等的强类型语言,多线程的使用十分普遍,但对于php来说,我们用得十分之少,因为在我们固定的思维里认为PHP 普遍都是单线程模型,并不适合多线程领域,花些时间翻了几个多线程的项目源码之后,发现 PHP 的多线程也颇有可取之处,活用起来,用来解决某些问题竟然非常适合。


1、 概念

线程(thread) 是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,线程自己不拥有系统资源,它与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。每一个程序都至少有一个线程,那就是程序本身,通常称为主线程。线程是程序中一个单一的顺序控制流程。 在单个程序中同时运行多个线程完成不同的工作,称为多线程。


2、php 中的多线程

PHP 5.3 以上版本,使用pthreads PHP扩展,做好相应的配置,就可以使PHP真正地支持多线程。重复性的循环任务用多线程处理,能够大大缩短程序执行时间

PHP 将线程 封装成了 Thread 类,线程的创建通过实例化一个线程对象来实现,由于类的封装性,变量的使用只能通过构造函数传入,而线程运算结果也需要通过类变量传出,以下是几个常用的 Thread 类方法

run():此方法是一个抽象方法,每个线程都要实现此方法,线程开始运行后,此方法中的代码会自动执行;

start():在主线程内调用此方法以开始运行一个线程;

join():各个线程相对于主线程都是异步执行,调用此方法会等待线程执行结束;

kill():强制线程结束;

isRunning():返回线程的运行状态,线程正在执行run()方法的代码时会返回 true;


3、调试多线程代码实例

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;


4、使用多线程对比for 循环的性能优化实例

class test_thread_run extends Thread {      public $url;      public $data;       public function __construct($url){          $this->url = $url;      }       public function run(){          if(($url = $this->url))          {              $this->data = model_http_curl_get($url);          }      }  }   function model_thread_result_get($urls_array) {      foreach ($urls_array as $key => $value)       {          $thread_array[$key] = new test_thread_run($value["url"]);          $thread_array[$key]->start();      }       foreach ($thread_array as $thread_array_key => $thread_array_value)       {          while($thread_array[$thread_array_key]->isRunning())          {              usleep(10);          }          if($thread_array[$thread_array_key]->join())          {              $variable_data[$thread_array_key] = $thread_array[$thread_array_key]->data;          }      }      return $variable_data;  }   function model_http_curl_get($url,$userAgent="") {      $userAgent = $userAgent ? $userAgent : 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2)';       $curl = curl_init();      curl_setopt($curl, CURLOPT_URL, $url);      curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);      curl_setopt($curl, CURLOPT_TIMEOUT, 5);      curl_setopt($curl, CURLOPT_USERAGENT, $userAgent);      $result = curl_exec($curl);      curl_close($curl);      return $result;  }   for ($i=0; $i < 100; $i++)   {       $urls_array[] = array("name" => "baidu", "url" => "http://www.baidu.com/s?wd=".mt_rand(10000,20000));  }   $t = microtime(true);  $result = model_thread_result_get($urls_array);  $e = microtime(true);echo "多线程耗时:".($e-$t)."秒<br>";  $t = microtime(true);  foreach ($urls_array as $key => $value)   {      $result_new[$key] = model_http_curl_get($value["url"]);  }  $e = microtime(true);echo "For循环耗时:".($e-$t)."秒<br>";

输出时间对比:


5、综上总结

重复性的循环任务用多线程处理在多进程开启的异步执行情况下,能够大大缩短程序执行时间


6、应用场景

        1、一个程序中多次请求接口获取数据。

2、发送大量的邮件,短信,或者其他的通知信息。

3、多次读取整块文件。

4、大计算量的代码。


7、多线程的局限性


多线程的优化是很多,可是无脑使用多线程并不能提升程序的执行效率,因为线程的创建和销毁、上下文切换、线程同步等也是有性能损耗的,耗费时间可能比顺序执行的代码还多。如:

一个从1累加到50000的函数素sumSmall

上图是在主线程内执行了三次 sumSmall 和三个线程分别执行 sumSmall ,再将结果同步到一个线程的时间对比,我们会发现只在主线程执行的时间反而更短,三个线程创建、切换、同步的时间远远大过了线程异步执行节省的时间。

而函数 sumLarge 从1累加到5000000,下图同一线程执行三次和三个线程执行的耗时:

所以,在设计代码时合理使用多线程,不可盲目,让多线程发挥出它应有的作用。


上一篇: 无

微信关注

获取更多技术咨询