婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > PHP生成器(generator)和協程的實現方法詳解

PHP生成器(generator)和協程的實現方法詳解

熱門標簽:電銷機器人-快迭智能 哈爾濱400電話辦理到易號網 高識別電銷機器人 合肥外呼系統app 沈陽人工智能電銷機器人公司 h5 地圖標注 智能外呼電銷系統 寶安400電話辦理 拉薩打電話機器人

本文實例講述了PHP生成器(generator)和協程的實現方法。分享給大家供大家參考,具體如下:

先說一些廢話

PHP 5.5 以來,新的諸多特性又一次令 PHP 煥發新的光彩,雖然在本文寫的時候已是 PHP 7 alpha 2 發布后的一段時間,但此時國內依舊是 php 5.3 的天下。不過我認為新的特性遲早會因為舊的版本的逐漸消失而變得越發重要,尤其是 PHP 7 的正式版出來后,因此本文的目的就是為了在這之前,幫助一些 PHPer 了解一些他們從沒有了解的東西。所以打算將以本篇作為博客中 PHP 知識補全 系列文章的開篇。

其實在寫本文之前,我對生成器以及基于此特性延伸出來的 php 的協程實現并沒有比較直觀的了解,主要是我個人水平并不是很高,屬于典型的剛入了門的 PHPer。所以在看了前段時間鳥哥(laruence)博客中對協程的講解(參考鏈接:《PHP中使用協同程序實現合作多任務》)后,在我個人對本篇的理解上,針對那些比較難以理解的概念(包括我個人在理解這一概念的時候的難點),以一個更為通俗的方式去講明白。當然由于本人也是剛剛去學習這一概念,所以有些不得當的地方在所難免,希望大神看見了請不吝賜教。

一切從 Iterator 和 Generator 開始

為便于新入門開發者理解,本文一半篇幅是講述迭代器接口(Iterator)和 Generator 類的,對此已經理解的話,可以直接跳過。

迭代和迭代器

在理解本文大多數概念前,有必要知道迭代和迭代器。事實上,迭代大家都知道是什么,可是我不知道(真的,在此之前對這個概念沒有系統了解)。迭代是指反復執行一個過程,每執行一次叫做一次迭代。實際上我們經常做這種事情,比如:

?php
$mapping = [
  'red'  => '#FF0000',
  'green' => '#00FF00',
  'blue' => '#0000FF'
];
foreach ($mapping as $key => $value) {
  printf("key: %d - value: %s\n", $key, $value);
}

我們可以看到通過 foreach 對數組遍歷并迭代輸出其內容。在這一環節中,我們需要關注的重點是數組。雖然我們迭代的過程是 foreach 語句中的代碼塊,但實際上數組 $mapping 在每一次迭代中發生了變化,意味著數組內部也存在著一次迭代。如果我們把數組看做一個對象,foreach 實際上在每一次迭代過程都會調用該對象的一個方法,讓數組在自己內部進行一次變動(迭代),隨后通過另一個方法取出當前數組對象的鍵和值。這樣一個可通過外部遍歷其內部數據的對象就是一個迭代器對象,其遵循的統一的訪問接口就是迭代器接口(Iterator)。

PHP 提供了一個統一的迭代器接口。關于迭代器 PHP 官方文檔有更為詳細的描述,建議去了解。

interface Iterator extends Traversable
{
  /**
   * 獲取當前內部標量指向的元素的數據
   */
  public mixed current ( void )
  /**
   * 獲取當前標量
   */
  public scalar key ( void )
  /**
   * 移動到下一個標量
   */
  public void next ( void )
  /**
   * 重置標量
   */
  public void rewind ( void )
  /**
   * 檢查當前標量是否有效
   */
  public boolean valid ( void )
}

我們來給出一個實例,去實現一個簡單的迭代器:

class Xrange implements Iterator
{
  protected $start;
  protected $limit;
  protected $step;
  protected $i;
  public function __construct($start, $limit, $step = 0)
  {
    $this->start = $start;
    $this->limit = $limit;
    $this->step = $step;
  }
  public function rewind()
  {
    $this->i = $this->start;
  }
  public function next()
  {
    $this->i += $this->step;
  }
  public function current()
  {
    return $this->i;
  }
  public function key()
  {
    return $this->i + 1;
  }
  public function valid()
  {
    return $this->i = $this->limit;
  }
}

通過 foreach 遍歷來看看這個迭代器的效果:

foreach (new Xrange(0, 10, 2) as $key => $value) {
  printf("%d %d\n", $key, $value);
}

輸出:

1 0
3 2
5 4
7 6
9 8
11 10

至此我們看到了一個迭代器的實現。一些人在了解這一特性會很激動的將其應用在實際項目中,但有些則疑惑這有什么卵用呢?迭代器只是將一個普通對象變成了一個可被遍歷的對象,這在有些時候,如一個對象 StudentsContact,這個對象是用于處理學生聯系方式的,通過 addStudent 方法注冊學生,通過 getAllStudent 獲取全部注冊的學生聯系方式數組。我們以往遍歷是通過 StudentsContact::getAllStudent() 獲取一個數組然后遍歷該數組,但是現在有了迭代器,只要這個類繼承這個接口,就可以直接遍歷該對象獲取學生數組,并且可以在獲取之前在類的內部就對輸出的數據做好處理工作。

當然用處遠不止這么點,但在這里就不過多糾結。有一個在此基礎上更為強大的東西,生成器。

生成器,Generator

雖然迭代器僅需繼承接口即可實現,但依舊很麻煩,我們畢竟需要定義一個類并實現該接口所有方法,這十分繁瑣。在一些情景下我們需要更簡潔的辦法。生成器提供了一種更容易的方法來實現簡單的對象迭代,相比較定義類實現 Iterator 接口的方式,性能開銷和復雜性大大降低。

PHP 官方文檔這樣說的:

生成器允許你在 foreach 代碼塊中寫代碼來迭代一組數據而不需要在內存中創建一個數組, 那會使你的內存達到上限,或者會占據可觀的處理時間。相反,你可以寫一個生成器函數,就像一個普通的自定義函數一樣, 和普通函數只返回一次不同的是, 生成器可以根據需要 yield 多次,以便生成需要迭代的值。

一個簡單的例子就是使用生成器來重新實現 range() 函數。 標準的 range() 函數需要在內存中生成一個數組包含每一個在它范圍內的值,然后返回該數組, 結果就是會產生多個很大的數組。 比如,調用 range(0, 1000000) 將導致內存占用超過 100 MB。

做為一種替代方法, 我們可以實現一個 xrange() 生成器, 只需要足夠的內存來創建 Iterator 對象并在內部跟蹤生成器的當前狀態,這樣只需要不到1K字節的內存。

官方文檔給了上文對應的例子,我們在此簡化了一下:

function xrange($start, $limit, $step = 1) {
  for ($i = $start; $i = $limit; $i += $step) {
    yield $i + 1 => $i; // 關鍵字 yield 表明這是一個 generator
  }
}
// 我們可以這樣調用
foreach (xrange(0, 10, 2) as $key => $value) {
  printf("%d %d\n", $key, $value);
}

可能你已經發現了,這個例子的輸出和我們前面在說迭代器的時候那個例子結果一樣。實際上生成器生成的正是一個迭代器對象實例,該迭代器對象繼承了 Iterator 接口,同時也包含了生成器對象自有的接口,具體可以參考 Generator 類的定義。

當一個生成器被調用的時候,它返回一個可以被遍歷的對象.當你遍歷這個對象的時候(例如通過一個foreach循環),PHP 將會在每次需要值的時候調用生成器函數,并在產生一個值之后保存生成器的狀態,這樣它就可以在需要產生下一個值的時候恢復調用狀態。

一旦不再需要產生更多的值,生成器函數可以簡單退出,而調用生成器的代碼還可以繼續執行,就像一個數組已經被遍歷完了。

我們需要注意的關鍵是 yield,這是生成器的關鍵。我們通過上面例子,可以看得出,yield 會將當前一個值傳遞給 foreach,換句話說,foreach 每一次迭代過程都會從 yield 處取一個值,直到整個遍歷過程不再存在 yield 為止的時候,遍歷結束。

我們也可以發現,yield 和 return 都會返回值,但區別在于一個 return 是返回既定結果,一次返回完畢就不再返回新的結果,而 yield 是不斷產出直到無法產出為止。

實際上存在 yield 的函數返回值返回的是一個 Generator 對象(這個對象不能手動通過 new 實例化),該對象實現了 Iterator 接口。那么 Generator 自身有什么獨特之處?繼續看:

yield

字面上解釋,yield 代表著讓位、讓行。正是這個讓行使得通過 yield 實現協程變得可能。

生成器函數的核心是 yield 關鍵字。它最簡單的調用形式看起來像一個 return 申明,不同之處在于普通 return 會返回值并終止函數的執行,而 yield 會返回一個值給循環調用此生成器的代碼并且只是暫停執行生成器函數。

yield 和 return 的區別,前者是暫停當前過程的執行并返回值,而后者是中斷當前過程并返回值。暫停當前過程,意味著將處理權轉交由上一級繼續進行,直至上一級再次調用被暫停的過程,該過程則會從上一次暫停的位置繼續執行。這像是什么呢?如果讀者在讀本篇文章之前已經在鳥哥的文章中粗略看過,應該知道這很像是一個操作系統的進程調度管理,多個進程在一個 CPU 核心上執行,在系統調度下每一個進程執行一段指令就被暫停,切換到下一個進程,這樣看起來就像是同時在執行多個任務。

但僅僅是如此還遠遠不夠,yield 更重要的特性是除了可以返回一個值以外,還能夠接收一個值!

function printer()
{
  while (true) {
    printf("receive: %s\n", yield);
  }
}
$printer = printer();
$printer->send('hello');
$printer->send('world');

上述例子輸出內容為:

receive: hello
receive: world

參考 PHP 官方中文文檔:生成器 對象 我們可以得知 Generator 對象除了實現 Iterator 接口中的必要方法以外,還有一個 send 方法,這個方法就是向 yield 語句處傳遞一個值,同時從 yied 語句處繼續執行,直至再次遇到 yield 后控制權回到外部。

我們通過之前也了解了一個問題,yield 可以在其位置中斷并返回一個值,那么能不能同時進行 接收返回 呢?當然,這可是實現協程的根本。我們對上述代碼做出修改:

?php
function printer()
{
  $i = 0;
  while (true) {
    printf("receive: %s\n", (yield ++$i));
  }
}
$printer = printer();
printf("%d\n", $printer->current());
$printer->send('hello');
printf("%d\n", $printer->current());
$printer->send('world');
printf("%d\n", $printer->current());

輸出內容如下:

1
receive: hello
2
receive: world
3

current 方法是迭代器( Iterator )接口必要的方法,foreach 語句每一次迭代都會通過其獲取當前值,而后調用迭代器的 next 方法。我們為了使程序不會無限執行,手動調用 current 方法獲取值。

上述例子已經足以表示 yield 在那一個位置作為雙向傳輸的 工具,已具備實現協程的條件。

協程

這一部分我不打算長篇大論,本文開頭已經給出了鳥哥博客中更為完善的文章,本文的目的是出于補充對 Generator 的細節。

我們要知道,對于單核處理器,多任務的執行原理是讓每一個任務執行一段時間,然后中斷、讓另一個任務執行然后在中斷后執行下一個,如此反復。由于其執行切換速度很快,讓外部認為多個任務實際上是 “并行” 的。

鳥哥那篇文章這么說道:

多任務協作這個術語中的 “協作” 很好的說明了如何進行這種切換的:它要求當前正在運行的任務自動把控制傳回給調度器,這樣就可以運行其他任務了。這與 “搶占” 多任務相反, 搶占多任務是這樣的:調度器可以中斷運行了一段時間的任務, 不管它喜歡還是不喜歡。協作多任務在 Windows 的早期版本 (windows95) 和 Mac OS 中有使用, 不過它們后來都切換到使用搶先多任務了。理由相當明確:如果你依靠程序自動交出控制的話,那么一些惡意的程序將很容易占用整個CPU,不與其他任務共享。

我們結合之前的例子,可以發現,yield 作為可以讓一段任務自身中斷,然后回到外部繼續執行。利用這個特性可以實現多任務調度的功能,配合 yield 的雙向通訊功能,以實現任務和調度器之間進行通信。

這樣的功能對于讀寫和操作 Stream 資源時尤為重要,我們可以極大的提高程序對于并發流資源的處理能力,比如實現 tcp server。以上在 《PHP中使用協同程序實現合作多任務》 有更為詳盡的例子。本文不再贅述。

總結

PHP 自 5.4 到如今愈發穩定的 PHP 7,可以看到許多的新特性令這門語言愈發強大和完善,逐漸從純粹的 Web 語言變得有著更為廣泛的適用面,作為一枚 PHPer 的確不應當止步不前,我們依然有很多的東西需要不斷學習和加強。

雖然 “PHP 是世界上最好的語言” 這句話只是個調侃,但不可否認 PHP 即使不是最好,但也在努力變好的事實,對吧?

更多關于PHP相關內容感興趣的讀者可查看本站專題:《php常用函數與技巧總結》、《php字符串(string)用法總結》、《PHP數組(Array)操作技巧大全》、《PHP數據結構與算法教程》及《php程序設計算法總結》

希望本文所述對大家PHP程序設計有所幫助。

您可能感興趣的文章:
  • PHP Web表單生成器案例分析
  • PHP迭代器和生成器用法實例分析
  • PHP生成器功能與用法實例分析
  • PHP中你可能忽略的性能優化利器:生成器
  • PHP十六進制顏色隨機生成器功能示例
  • PHP新特性詳解之命名空間、性狀與生成器
  • php驗證碼生成器
  • thinkPHP連接sqlite3數據庫的實現方法(附Thinkphp代碼生成器下載)
  • PHP5.5迭代生成器用法實例詳解
  • PHP 生成器的使用詳解

標簽:梅州 山東 張家口 成都 林芝 巴中 泰州 威海

巨人網絡通訊聲明:本文標題《PHP生成器(generator)和協程的實現方法詳解》,本文關鍵詞  PHP,生,成器,generator,和,協程,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《PHP生成器(generator)和協程的實現方法詳解》相關的同類信息!
  • 本頁收集關于PHP生成器(generator)和協程的實現方法詳解的相關信息資訊供網民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    成人免费视频在线观看| 亚洲1区2区3区视频| 亚洲va国产天堂va久久en| 日韩欧美国产麻豆| 国产在线视视频有精品| 捆绑变态av一区二区三区| 欧美欧美午夜aⅴ在线观看| 337p日本欧洲亚洲大胆色噜噜| 色综合天天性综合| 一区二区三区中文字幕电影| 亚洲精选免费视频| 午夜国产不卡在线观看视频| 91色在线porny| 亚洲最大成人综合| 精品国产一区二区三区忘忧草| 成人av高清在线| 欧美日韩国产美女| 国产99久久久国产精品潘金网站| 亚洲曰韩产成在线| 久久综合久色欧美综合狠狠| av一区二区不卡| 日韩国产精品91| 国产精品美日韩| 日韩免费观看高清完整版| av资源站一区| 亚洲午夜精品一区二区三区他趣| 久久久精品2019中文字幕之3| 欧美视频一区二区在线观看| eeuss鲁片一区二区三区在线看| 亚洲午夜精品在线| 亚洲图片欧美激情| 久久久久久久久久电影| 欧美高清视频一二三区| 亚洲国产精品人人做人人爽| 国产精品久久精品日日| 久久久久久久久伊人| 日韩欧美国产一区在线观看| 成人永久aaa| 午夜精品免费在线| 国产欧美久久久精品影院| 日韩一区二区在线观看视频| 欧美日韩在线直播| 国内精品免费在线观看| 一区二区中文视频| 97久久精品人人澡人人爽| 青青草精品视频| 亚洲素人一区二区| 日韩在线a电影| 天天影视涩香欲综合网| 亚洲综合一二三区| 一区二区三区四区高清精品免费观看 | 韩国精品在线观看| 日精品一区二区三区| 亚洲国产电影在线观看| 丝瓜av网站精品一区二区| 国产一区欧美日韩| 日韩一区和二区| 欧洲色大大久久| 国产精品1区2区3区| 国产成人av一区| 成人免费看视频| 91蜜桃网址入口| 欧美调教femdomvk| 欧美综合一区二区| 欧美成人官网二区| 美女一区二区在线观看| 成人av影院在线| 精品国产一区二区国模嫣然| 日韩女优毛片在线| 欧美videos大乳护士334| 欧美va亚洲va在线观看蝴蝶网| 精品99999| 国产精品情趣视频| 一区二区三区在线视频免费观看| 一区二区不卡在线视频 午夜欧美不卡在 | 欧美一区二区免费| 久久欧美一区二区| 亚洲免费在线播放| 日韩电影一区二区三区四区| 国产一区二区三区电影在线观看 | 国产一区激情在线| 99久久99久久精品免费观看| 成人一区二区三区中文字幕| 欧美日韩一区三区四区| 欧洲生活片亚洲生活在线观看| 色天天综合色天天久久| 日韩亚洲欧美中文三级| 亚洲国产精品高清| 首页综合国产亚洲丝袜| 成人免费观看男女羞羞视频| 精品视频在线视频| 久久综合99re88久久爱| 亚洲一区视频在线观看视频| 国产精品综合av一区二区国产馆| 99久久久精品免费观看国产蜜| 欧美三级三级三级爽爽爽| 久久婷婷国产综合精品青草| 亚洲自拍另类综合| 91蝌蚪国产九色| 日精品一区二区三区| 久久精品国产精品亚洲红杏| 欧美精选一区二区| 国产精品久久久久久久蜜臀| 2021国产精品久久精品| 欧美人妖巨大在线| 国产一区二区三区国产| 中文字幕在线观看不卡视频| 成人免费精品视频| 日韩二区三区在线观看| 99综合影院在线| 欧美激情中文不卡| 99re视频精品| 精品一区二区影视| 偷窥国产亚洲免费视频| 亚洲精品亚洲人成人网 | 欧美精品一级二级| 国产精品家庭影院| 亚洲午夜一区二区| 欧美巨大另类极品videosbest| 国产亚洲精品免费| 精品国产一区a| 欧美色大人视频| 久久色.com| 午夜久久久影院| 色综合夜色一区| 欧美国产激情一区二区三区蜜月| 另类小说欧美激情| 538在线一区二区精品国产| 一区二区三区波多野结衣在线观看| 成人激情黄色小说| 日韩欧美不卡一区| 久久久久久久一区| 国模一区二区三区白浆| 欧美电影精品一区二区| 久久福利视频一区二区| 欧美成人在线直播| 激情丁香综合五月| 欧美xingq一区二区| 麻豆免费看一区二区三区| 欧美精品一级二级三级| 日韩黄色片在线观看| 日韩亚洲欧美高清| 婷婷综合在线观看| 久久久久久影视| 国产丶欧美丶日本不卡视频| 久久久精品国产免大香伊 | 亚洲女同一区二区| 欧美日韩精品免费观看视频 | 国产成人精品免费网站| 精品国产91亚洲一区二区三区婷婷| 欧美日韩第一区日日骚| 色婷婷久久综合| 福利视频网站一区二区三区| 国产日韩欧美精品一区| 不卡的av在线| 伊人一区二区三区| 欧美乱妇23p| 国产自产高清不卡| 亚洲精品中文字幕在线观看| 91精品国产综合久久久蜜臀粉嫩| 激情五月婷婷综合网| 中文字幕精品一区| 色呦呦国产精品| 亚洲免费av高清| 精品亚洲国产成人av制服丝袜| 欧美日韩久久久久久| 老司机免费视频一区二区三区| 91精品国产欧美一区二区18| 国产女主播在线一区二区| 国产成人av一区二区| 亚洲一区二区三区在线看| 精品久久久久久久久久久久久久久久久| 粉嫩在线一区二区三区视频| 亚洲国产日韩一区二区| 久久亚洲精精品中文字幕早川悠里| caoporen国产精品视频| 一区二区三区日韩在线观看| 777精品伊人久久久久大香线蕉| 成人污污视频在线观看| 久久99精品久久久久久久久久久久 | 欧美私人免费视频| 色网站国产精品| 97久久精品人人澡人人爽| 成人久久久精品乱码一区二区三区 | 亚洲午夜激情网页| 夜色激情一区二区| 亚洲不卡av一区二区三区| 五月婷婷综合激情| 日本不卡一区二区| 日本va欧美va欧美va精品| 久久精品国产免费| 国产91精品免费| 色综合久久综合网97色综合| 欧美视频一区二| 日韩一级黄色片| 国产拍欧美日韩视频二区| 成人欧美一区二区三区视频网页| 一区二区三区不卡在线观看| 亚洲成a人v欧美综合天堂| 麻豆成人免费电影|