>  기사  >  백엔드 개발  >  PHP의 코루틴 및 차단에 대한 심층적인 이해

PHP의 코루틴 및 차단에 대한 심층적인 이해

黄舟
黄舟원래의
2017-08-11 11:37:001620검색

이 글에서는 주로 PHP의 코루틴과 차단에 대한 이해와 생각을 소개합니다. 이 글에서는 PHP를 배우거나 사용할 수 있는 특정 참고 학습 가치를 아래에서 확인할 수 있습니다. .함께 배워봅시다.

머리말

이 글은 주로 PHP의 코루틴과 블로킹에 대한 이해와 생각을 소개하고 참고와 학습을 위해 공유합니다. 아래에서 할 말은 많지 않으나 자세한 소개를 살펴보겠습니다.

프로세스, 스레드, 코루틴

프로세스, 스레드, 코루틴에 대한 매우 상세하고 풍부한 블로그나 학습 리소스가 있으므로 여기서는 이에 대해 간략히 소개하지 않겠습니다.

  • 프로세스에는 자체 독립적인 힙과 스택이 있으며 힙이나 스택을 공유하지 않습니다. 프로세스는 운영 체제에 의해 예약됩니다.

  • 스레드에는 자체 독립 스택과 공유 힙이 있습니다. 힙은 공유되지만 스택은 공유되지 않습니다. 스레드도 운영 체제에 의해 예약됩니다.

  • 코루틴은 스레드처럼 힙을 공유하지만 스택은 공유하지 않습니다. 코루틴은 프로그래머가 코루틴 코드에서 명시적으로 예약합니다.

PHP에서 코루틴 Yield의 기본 구현

Yield의 기본 구현은 생성기 클래스이고 반복자 클래스는 반복자 인터페이스의 구현입니다.


Generator implements Iterator {
 public mixed current ( void ) // 返回当前产生的值
 public mixed key ( void ) // 返回当前产生的键
 public void next ( void ) // 生成器继续执行
 public void rewind ( void ) // 重置迭代器,如果迭代已经开始了,这里会抛出一个异常。
   // renwind的执行将会导致第一个yield被执行, 并且忽略了他的返回值.
 public mixed send ( mixed $value ) // 向生成器中传入一个值,并且当做 yield 表达式的结果,然后继续执行生成器。如果当这个方法被调用时,生成器 
   // 不在 yield 表达式,那么在传入值之前,它会先运行到第一个 yield 表达式。
 public void throw ( Exception $exception ) // 向生成器中抛入一个异常
 public bool valid ( void ) // 检查迭代器是否被关闭
 public void __wakeup ( void ) // 序列化回调,抛出一个异常以表示生成器不能被序列化。
}

기반 그가 구현한 코루틴 다중 작업 스케줄링에 대해 예를 들어 차단에 대한 내 생각을 이야기하겠습니다.

간단한 예약 실행 작업 사용자 정의의 예:

(이 예는 위의 Brother Niao가 구현한 코루틴 스케줄링 코드에 의존해야 함)


class timer {
 private $start = 0; // 定时开始时间
 private $timer; // 间隔的时间差,单位秒
 private $value = 0; // 产生的结果值
 private $callback; // 异步回调
 private $isEnd = false; // 当前定时器任务是否结束
 public function __construct($timer,callable $callback)
 {
 $this->start = time();
 $this->timer = $timer;
 $this->callback = $callback;
 }
 public function run() {
 if($this->valid()) {
 $callback = $this->callback;
 $callback($this->value ++,$this);
 $this->start = time();
 }
 }
 /**
 * 定时执行检查
 */
 public function valid() {
 $end = time();
 if($end - $this->start >= $this->timer) {
 return true;
 } else {
 return false;
 }
 }
 public function setEnd($isEnd) {
 $this->isEnd = $isEnd;
 }
 public function getEnd() {
 return $this->isEnd;
 }
}

/**
 * 模拟阻塞的协程1
 *
 */
function taskObject1() {
 $timer = new timer(1,function($value,timer $timer) {
 if($value >= 5) {
 $timer->setEnd(true);
 }
 echo &#39;<br>&#39;.&#39;A &#39;.$value;
 });
 $tid = (yield getTaskId());
 while (true) {
 if($timer->getEnd() == true) {
 break;
 }
 yield $timer->run();
 }
}
/**
 * 模拟阻塞的协程2
 *
 */
function taskObject2() {
 $timer = new timer(2,function($value,timer $timer) {
 if($value >= 3) {
 $timer->setEnd(true);
 }
 echo &#39;<br>&#39;.&#39;B &#39;.$value;
 });
 $tid = (yield getTaskId());
 while (true) {
 if($timer->getEnd() == true) {
 break;
 }
 yield $timer->run();
 }
}
$scheduler = new Scheduler;
$scheduler->newTask(taskObject1());
$scheduler->newTask(taskObject2());
$scheduler->run();

위의 구현은 다음과 같습니다.

  • 두 개를 생성합니다. 작업은 병렬로 실행되며 각 작업은 실행 중에 몇 초 동안 차단되도록 시뮬레이션됩니다.

  • 코루틴 전환 시 원활한 전환이 가능하며 작업 차단이 서로 영향을 미치지 않습니다.

위 작업을 왜 해야 하나요? 코루틴 구현이 매우 강력하고 흥미롭고 멀티 태스킹을 병렬로 활성화할 수 있지만 작업 중 하나에서 시스템 함수 sleep()을 호출하면 차단 작업으로 인해 실제로 코루틴 전환도 마찬가지입니다. 그런 다음 코루틴 차단도 시뮬레이션하고 싶지만 실행 가능한지 확인하기 위해 차단을 유발하지 않습니다. PHP 자체는 코루틴 호출을 지원하기 위한 생성기만 제공합니다. 확장에 의존하지 않는 경우 다중 스레드 프로그램 구현 방법을 제공하지 않으며 Java만큼 강력하지 않으며 하위 스레드를 열어 구현할 수 있습니다.

Java의 하위 스레드는 독립적으로 실행되고 서로를 차단하지 않는다는 인상을 받았기 때문에 PHP가 멀티스레딩과 유사한 메커니즘을 구현할 수 있으므로 호출 프로세스 중에 비차단을 달성할 수 있을까요?

sleep() 的时候,阻塞任务会阻止协程切换,其实从协程的实现原理上来书也是这么回事。

那么,我也就想模拟协程阻塞,但是不产生阻塞看是否可行。PHP本身只提供了生成器为协程调用提供了支撑,如果不依赖扩展,没有提供多线程的程序实现方式,没有java那么强大,可以开子线程进行实现。

我印象中java的子线程是独立执行且不会相互阻塞的,所以我在想,PHP既然可以实现类似于多线程这样的机制,那么能不能实现调用过程中非阻塞呢?

经过这样一个实现和思考,一开始是陷入了一个误区的,是由于PHP原生函数 sleep() 이렇게 구현하고 생각하다가 처음에는 오해에 빠졌습니다. 그건 PHP 네이티브 함수인 sleep()이 막혀서 생긴 오해였습니다. 실제로 비차단을 달성하거나 비동기식으로 구현하려면 기본 언어에 의존해야 합니다.

나중에 알아낸 사실은 특정 메서드나 함수가 실행 중에 차단되므로 현재 메서드를 사용자 정의 메서드로 교체하고 비차단으로 만듭니다(전체 코루틴 스케줄링과 비교). ? 예를 들어, 위의 예약된 실행을 직접 구현했습니다.

한편, 코루틴 스케줄링 자체의 목적은 작업 실행 프로세스를 가능한 한 작은 조각으로 나누어 실행을 빠르게 전환하고 병렬성을 달성하는 것입니다. 이러한 관점에서 코루틴은 프로그래밍 아이디어로도 간주되어야 합니다.

다음은 실행을 위해 프로그램을 가능한 한 작은 조각으로 자르는 예입니다.


// 一个简单的例子
<?php
function xrange($start, $end, $step = 1) {
 for ($i = $start; $i <= $end; $i += $step) {
 yield $i;
 }
}
 
foreach (xrange(1, 1000000) as $num) {
 echo $num, "\n";
}

이 예는 range를 사용하여 큰 정수 배열을 생성하는 원래 방법을 슬라이싱 실행으로 전환하는 것입니다. 즉, 탐색할 때 지정된 값을 가져옵니다. 코드 관점에서 볼 때 메모리 소비는 이전에 비해 매우 적습니다.

요약

위 내용은 PHP의 코루틴 및 차단에 대한 심층적인 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.