## 異步通知,那我要怎么通知你啊?
[Java帝國之撥云見日識回調 - 碼農翻身](http://mp.weixin.qq.com/s?__biz=MzAxOTc0NzExNg==&mid=2665513481&idx=1&sn=e1ebb1389eda4a36328ce6e8ad833b2f&chksm=80d67a4ab7a1f35c5218f2c62cd59e539d6053cfc81a3afc33b300d9cd3b70bba661ea9cb851&scene=21#wechat_redirect)
>[danger] 他拎了兩瓶好酒去找FileIO商量: “兄弟, 我聽說有一種異步保存的辦法, 你那邊能不能用下? 保存數據的時候起一個線程, 把主線程讓回給我,保存好了再通知我,我也不用老是等你,是吧?”
FIleIO想了想說:“這樣確實可以解決問題,但每天找我保存數據的人也很多,**而且我也不知道在完成數據的寫入之后怎么通知你呢?**”
小張把兩瓶好酒往前一推, “我們關系這么好,你再開個專屬我的方法唄,**我在調用你的saveStrToFile方法的時候順便把我的實例給你**,你搞完之后通過我的實例調用我的方法通知我就行啦。就調我的onResult()這個方法吧。這事要保密, 天知地知你知我知就行了”。
怎么通知,我調用你的時候就可以跟你說好啊。
我讓你做一件事情,但是你做得很慢,并不能夠立馬返回給我結果,害我一直在那兒等著你給我返回結果,什么都做不了,我又是個急性子,真是郁悶。
程序是自上而下順序執行的,很多時候后一步的操作依賴于前一步操作的返回結果,所以必須按照順序依次執行,因為我們的代碼就是這么寫的。
如果我不想等,那我就需要把操作拆分解耦,解耦我可以做到,就是讓后面的操作不一定非要等到前面操作的完成,不是非要依賴于前面的返回結果,也就是我不用等你了。把耗時的操作,對整體結構非關鍵部分的操作異步執行。
好想法。
可是異步執行完,你要通知我,對我說你幫我做好了啊。
我為什么要你通知我你做好了呢,換句話說,我為什么要知道異步的事情做好了呢?
因為,事情做好了,不管什么結果,我還要接著處理一下啊,不是說異步我丟給你了我就不管了,我只是暫時沒空等你,我希望你給我開個后門,在背后幫我完成,做好了你還是要跟我說的,然后我還要繼續處理的。
可是問題是,我做好了怎么通知你呢,并且到時候你還在不在我都不知道?
轉換一下思路:一切是為了解決問題的,而不在于解決問題的方式。
你想讓我做好后通知你,不就是你還想處理一下我的執行結果嗎?既然這樣,你讓我做事的時候,直接把你本來想要處理的過程實例也一并跟我說了不就好了嗎,這樣到時候我做完了就知道幫你處理的,不然到時候我還不知道要怎么找你呢,也不知道那個時候你還在不在線。你說這樣可以嗎?
是啊,我怎么沒想到呢,哈哈,你真聰明,我太笨了。那我需要給你傳兩個參數哈,一個是需要你幫我處理異步任務,一個是完成后的處理實例,這樣到時候你就可以幫我處理了,我也不用在什么地方等著你來通知我了,哈哈。
你不用擔心到時候怎么找我,我也不用在什么地方一直等你通知我。真好。
解決問題的本質是要認清楚問題的本質,有時候固有思維容易影響我們,所以要跳出固有的思維方式,用最直接的方式解決問題是最有效的方式。
* * * * *
上面有一個問題沒說,我怎么做到把 我要你幫我做的任務發給你?
web不支持這種方式,所以這時候需要請出隊列了。
> 其實這個AJAX是一樣的,在進行異步請求的時候就把回調的匿名函數當做參數傳給它了,在等待服務端返回的過程中并不會紫塞主線程,這是一個異步的操作,響應完成后它就會自己調用之前傳遞給它的匿名函數。其實ajax就像是一個運行在客戶端的客戶端軟件一樣,它支持這種模式,原理是因為客戶端在主線程之外還有一個事件循環的機制,但是web服務端,B/S這種架構的軟件并不支持這種模式,一個請求處理完成后必須立即返回給客戶端,客戶端才能夠收到http響應,才算完成一次請求,并且http是無狀態的,服務端不能夠和客戶端進行主動通信,這不是web服務能力的問題,而是由web服務的本質所決定的,所以這種異步,回調的方式想要用在服務端就要換一種方式了,那就是隊列。
[Java 帝國之消息隊列](http://mp.weixin.qq.com/s?__biz=MzAxOTc0NzExNg==&mid=2665513507&idx=1&sn=d6db79c1ae03ba9260fb0fb77727bb54&chksm=80d67a60b7a1f376e7ad1e2c3276e8b565f045b1c7e21ef90926f69d99f969557737eb5d8128&scene=21#wechat_redirect)
> 晚上到家,小張苦思憫想: 原來訂單系統和庫存系統都在一個虛擬機中, 處理起來很方便, 但是現在是個遠程的Web服務, 酒鬼小李不給我返回結果, 我就沒法結束, 這是典型的同步操作, 能不能改成異步的呢?
我把一個訂單包裹發給小李, 他什么時候處理我就不用管了, 這樣我這邊的效率就會大大的提高! 可是現在的Web服務并不支持這種方式, 我怎么才能把包裹發過去呢?
* * * * *
[小李的數據庫之旅(上)](http://mp.weixin.qq.com/s?__biz=MzAxOTc0NzExNg==&mid=2665513312&idx=1&sn=f0c3e5623cc1042fa486c91c5d0ec6d4&scene=21#wechat_redirect)
>[danger] “所有計算機的問題都可以通過增加一個中間層來解決”
* * * * *
### 思考
web服務中,客戶端一次請求后,服務端應該立馬返回并斷開,越快越好,這樣用戶就會感覺很快,PHP有ob_flush ,其實也可以在不斷開,一直往瀏覽器推送數據,但是這樣的體驗并不好,因為用戶如果感覺瀏覽器加載的圈圈一直在轉的話,他會覺得這個網站打開好慢,因為在所有人的主觀意識中,網站應該就是建立請求后,響應完成后應該就立馬斷開,這樣才體現網站訪問速度很快。并且如果你想用AJAX和ob_flush來配合做,其實也不現實,[它對ajax是無效的](http://blog.csdn.net/u011832039/article/details/51387548),因為ajax是要在服務端響應完成后才執行的,所以服務端軟件和客戶端軟件有很大的本質區別,不想客戶端軟件,進程在本地,異步使用起來就很方便,在服務端就要轉變一些思路,換一種方式了。
### 參考:
[定時-時鐘-阻塞 · php筆記 · 看云](http://www.hmoore.net/xiak/php-node/400090)
[多進程/多線程 · php筆記 · 看云](http://www.hmoore.net/xiak/php-node/419460)
[nginx、swoole高并發原理初探 - 暢想代碼 - SegmentFault](https://segmentfault.com/a/1190000007614502?utm_source=coffeephp.com)
[javascript - 究竟能不能用死循環?或者其實我們就活在一個死循環的世界中? - SegmentFault](https://segmentfault.com/q/1010000009586182)
[php與ajax交互——實現php實時返回結果給ajax,并在后臺保持繼續運行的方法](http://blog.csdn.net/u011832039/article/details/51387548)
[Nginx+Php-fpm運行原理詳解](http://blog.csdn.net/u013474436/article/details/52972699)
[異步編程那些事 - 顏海鏡](http://yanhaijing.com/javascript/2017/08/02/talk-async/)
[怎樣理解阻塞非阻塞與同步異步的區別?-IT老友的回答-悟空問答](https://www.wukong.com/answer/6492953923190522125/?iid=12619555732&app=news_article&share_ansid=6492953923190522125&wxshare_count=1&tt_from=weixin&utm_source=weixin&utm_medium=toutiao_android&utm_campaign=client_share)
[hprose真的讓PHP實現異步了嗎?-悟空問答](https://www.wukong.com/question/6482944667104051469/?wxshare_count=1&tt_from=weixin&utm_source=weixin&utm_medium=topic_android&utm_campaign=client_share)
[異步與回調的設計哲學 - 掘金](https://juejin.im/post/58b599aa44d9040068628fb6)
[Node.js : 我只需要一個店小二 - 碼農翻身](https://mp.weixin.qq.com/s/BzrAacmJZEFRXE3vijCVQQ)
~~~
我的提問:
老大你好,我有個問題,node是通過事件回調來實現異步的,就跟前端寫js一樣的方式,但是在服務端這明顯的有問題啊,你那個 送客()也是在回調里面的,也就是說不能夠立即返回給前端,只有服務端完全響應完,瀏覽器才能收到200的狀態啊,不然網頁不一直處于加載狀態嗎?這樣ajax也得不到響應完成的狀態,那這些前臺還是需要等,這樣不一點意義都沒有啊,好糾結,在線等回復。我感覺web訪問式服務,要想實現異步處理任務的效果只能用隊列吧,你文中的效果其實跟瀏覽器端的js一樣,這種事件循環適應于客戶端軟件,這在B/S中行不通,不知道我的理解對不對。
回復:
待回復
~~~
#### 思考:
其實,我說的都是對的,只是理解上出了偏差,node異步是指在服務端,node本身是單進程的,不像php Nginx那種運行方式,所以為了提升并發服務能力,node必須的很好的支持異步操作,這個異步是指node單進程處理大量的訪問而需要進行異步處理,而不是針對于我問題中的情況,問題中的情況沒錯,都是對的,是只能使用隊列,才能讓服務端盡快返回,耗時的任務放到隊列才能是前端盡快得到響應,從而無需等待。
是我理解錯了node異步的意思,這里異步指的是處理請求和io的方式。比如php 30和個php-fpm進程,來30個請求,都是讀大文件的,那么第31個請求就暫時進不來了,而node只需要一個進程,也可以讓第31個人進來,第一個人讀文件異步讀,不影響第二個人更新資料,這就是node異步的體現。而不是我理解的在一個請求中,先把準備好的內容[先推送到瀏覽器](http://www.laruence.com/2011/02/13/1870.html),而后面腳本則繼續執行,這樣可以讓瀏覽器提前得到響應,或者與[nginx連接斷開](http://www.laruence.com/2011/04/13/1991.html),但當前php-fpm腳本不會結束,而是繼續執行耗時任務,異步根本不是這樣理解的,這種方式不叫異步,和異步沒關系,只是一種奇淫巧技而已,并沒有從根本上解決問題。
* * * * *
**將php與node這樣對比,本身就錯了,它們根本不是一個東西,不能這樣比較,一個php是web服務器中一個獨立的單元,而node.js腳本則可以代表整個web服務器,所以這兩者根本就沒有可比性。所以我這個問題真是愚蠢,根本就沒有弄清楚它們是什么嘛。**
PHP代碼是線性從上到下按順序執行的(可以預測代碼的執行順序),沒有事件的概念,所以效率很低,而node.js就不同了,JS天生的異步,所以某些情況下,性能會比PHP好。
>[danger] **node.js = Nginx + php**
* * * * *
> PHP 頁面沒有任何事件的概念,只有兩個事件也許有意義并且有用處,(1)URL調用事件,(2)URL調用完成事件。URL調用事件是通過運行PHP腳本處理,重點是,整個PHP腳本就是URL調用處理。當PHP腳本執行完成,生成了所有輸出,可以被看做是URL調用完成事件。為了處理這種事件,需要在PHP頁面末尾加上其他處理代碼。所以PHP頁面是可以看做是兩個事件之間的一大段無事件代碼,就像三明治一樣。
>
> 基本上PHP在做一件事情的時候需要等到其他事情的完成,這種方式效率非常低(讓計算機資源閑置了,沒有得到充分利用)。在PHP中如果有一些任務需要耗費太長時間,你只能一直等待該任務完成,沒有其他更快的向下執行的方式。
**回調函數:**
回調函數是一種電泳代碼時,將自己的代碼插入到被調用的函數的方法。它是在不修改函數本身代碼的情況下改變函數的行為的方法。
**事件與回調:**
一個事件可以跟回調函數聯系到一起,這也被叫做事件處理程序。事件處理程序會在一個事件發生時被執行。on()函數可以將一個事件和事件處理函數聯系到一起。
(摘自:《寫給PHP開發者的Node.js學習指南》)
* * * * *
[駁PHP優于Node.js的五大理由 - CNode技術社區](https://cnodejs.org/topic/51659db96d38277306d202a3)
> 回調真的惡心嗎?當你真的理解事件驅動的時候,你會發現回歸才是編程的本質,一切的結束都是回歸,而不是強求!
[Node.js和PHP運行機制對比 - NT.Wang - 博客園](https://www.cnblogs.com/NTWang/p/6271696.html)
> 誰的效率更高,通常情況下是這樣認為的,那就是,誰沒有讓cpu閑著,誰能最大限度的壓榨cpu資源,充分利用計算機的效能,誰的效率性能就更高。
[\[翻譯\]了解 NodeJS 看這一篇就夠了](http://mp.weixin.qq.com/s/QRsX6D6i00V5Vyh9k5fchw)
[異步編程需要“意識”](http://mp.weixin.qq.com/s/Pd4RDvjItxIf17EMetNz4Q)
[Node 定時器詳解](https://mp.weixin.qq.com/s/FZefHsoVqtkcjUJK3KwRFw)
last update:2018-2-12 01:22:07
- 開始
- 公益
- 更好的使用看云
- 推薦書單
- 優秀資源整理
- 技術文章寫作規范
- SublimeText - 編碼利器
- PSR-0/PSR-4命名標準
- php的多進程實驗分析
- 高級PHP
- 進程
- 信號
- 事件
- IO模型
- 同步、異步
- socket
- Swoole
- PHP擴展
- Composer
- easyswoole
- php多線程
- 守護程序
- 文件鎖
- s-socket
- aphp
- 隊列&并發
- 隊列
- 講個故事
- 如何最大效率的問題
- 訪問式的web服務(一)
- 訪問式的web服務(二)
- 請求
- 瀏覽器訪問阻塞問題
- Swoole
- 你必須理解的計算機核心概念 - 碼農翻身
- CPU阿甘 - 碼農翻身
- 異步通知,那我要怎么通知你啊?
- 實時操作系統
- 深入實時 Linux
- Redis 實現隊列
- redis與隊列
- 定時-時鐘-阻塞
- 計算機的生命
- 多進程/多線程
- 進程通信
- 拜占庭將軍問題深入探討
- JAVA CAS原理深度分析
- 隊列的思考
- 走進并發的世界
- 鎖
- 事務筆記
- 并發問題帶來的后果
- 為什么說樂觀鎖是安全的
- 內存鎖與內存事務 - 劉小兵2014
- 加鎖還是不加鎖,這是一個問題 - 碼農翻身
- 編程世界的那把鎖 - 碼農翻身
- 如何保證萬無一失
- 傳統事務與柔性事務
- 大白話搞懂什么是同步/異步/阻塞/非阻塞
- redis實現鎖
- 淺談mysql事務
- PHP異常
- php錯誤
- 文件加載
- 路由與偽靜態
- URL模式之分析
- 字符串處理
- 正則表達式
- 數組合并與+
- 文件上傳
- 常用驗證與過濾
- 記錄
- 趣圖
- foreach需要注意的問題
- Discuz!筆記
- 程序設計思維
- 抽象與具體
- 配置
- 關于如何學習的思考
- 編程思維
- 談編程
- 如何安全的修改對象
- 臨時
- 臨時筆記
- 透過問題看本質
- 程序后門
- 邊界檢查
- session
- 安全
- 王垠
- 第三方數據接口
- 驗證碼問題
- 還是少不了虛擬機
- 程序員如何談戀愛
- 程序員為什么要一直改BUG,為什么不能一次性把代碼寫好?
- 碎碎念
- 算法
- 實用代碼
- 相對私密與絕對私密
- 學習目標
- 隨記
- 編程小知識
- foo
- 落盤
- URL編碼的思考
- 字符編碼
- Elasticsearch
- TCP-IP協議
- 碎碎念2
- Grafana
- EFK、ELK
- RPC
- 依賴注入
- 科目一
- 開發筆記
- 經緯度格式轉換
- php時區問題
- 解決本地開發時調用遠程AIP跨域問題
- 后期靜態綁定
- 談tp的跳轉提示頁面
- 無限分類問題
- 生成微縮圖
- MVC名詞
- MVC架構
- 也許模塊不是唯一的答案
- 哈希算法
- 開發后臺
- 軟件設計架構
- mysql表字段設計
- 上傳表如何設計
- 二開心得
- awesomes-tables
- 安全的代碼部署
- 微信開發筆記
- 賬戶授權相關
- 小程序獲取是否關注其公眾號
- 支付相關
- 提交訂單
- 微信支付筆記
- 支付接口筆記
- 支付中心開發
- 下單與支付
- 支付流程設計
- 訂單與支付設計
- 敏感操作驗證
- 排序設計
- 代碼的運行環境
- 搜索關鍵字的顯示處理
- 接口異步更新ip信息
- 圖片處理
- 項目搭建
- 閱讀文檔的新方式
- mysql_insert_id并發問題思考
- 行鎖注意事項
- 細節注意
- 如何處理用戶的輸入
- 不可見的字符
- 抽獎
- 時間處理
- 應用開發實戰
- python 學習記錄
- Scrapy 教程
- Playwright 教程
- stealth.min.js
- Selenium 教程
- requests 教程
- pyautogui 教程
- Flask 教程
- PyInstaller 教程
- 蜘蛛
- python 文檔相似度驗證
- thinkphp5.0數據庫與模型的研究
- workerman進程管理
- workerman網絡分析
- java學習記錄
- docker
- 筆記
- kubernetes
- Kubernetes
- PaddlePaddle
- composer
- oneinstack
- 人工智能 AI
- 京東
- pc_detailpage_wareBusiness
- doc
- 電商網站設計
- iwebshop
- 商品規格分析
- 商品屬性分析
- tpshop
- 商品規格分析
- 商品屬性分析
- 電商表設計
- 設計記錄
- 優惠券
- 生成唯一訂單號
- 購物車技術
- 分類與類型
- 微信登錄與綁定
- 京東到家庫存系統架構設計
- crmeb
- 命名規范
- Nginx https配置
- 關于人工智能
- 從人的思考方式到二叉樹
- 架構
- 今日有感
- 文章保存
- 安全背后: 瀏覽器是如何校驗證書的
- 避不開的分布式事務
- devops自動化運維、部署、測試的最后一公里 —— ApiFox 云時代的接口管理工具
- 找到自己今生要做的事
- 自動化生活
- 開源與漿果
- Apifox: API 接口自動化測試指南