Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 美女黄视频网站,嫩草影院一二三永久在线观看,91久久精品一区二区三区

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          李開復張亞勤重磅對談,頂級AI大咖共話未來,200萬網友在線圍觀

          輯部 發自 凹非寺

          量子位 報道 | 公眾號 QbitAI

          “一起花光比爾蓋茨的8000萬美金,來不來?”

          23年前,李開復跟張亞勤這樣“畫餅”,于是亞洲最牛的計算機研究院就此誕生!

          如今,他們一個是最具影響力的VC代表,他創辦的創新工場已成為很多技術創新和前沿科技企業的精準捕手,他出版的書籍,不少登上暢銷書排行榜。

          另一個則是清華智能產業研究院院長、清華智能科學講席教授,前不久他剛當選中國工程院外籍院士。加之此前美國藝術與科學院院士、澳洲國家工程院院士,成為“三院院士”

          結果在MEET2022智能未來大會的現場,兩人時隔多年首次同臺,在近兩百萬觀眾面前,揭秘相識往事,也分享了各自對于科技發展趨勢的看法。

          從網友的反應上看,這次巔峰對話足以滿足他們的期待。甚至還吸引了數十家主流媒體關注報道。

          巔峰對話還有哪些亮點?以及十余位頂級AI大咖分享更多精彩內容,老樣子,我們詳細道來,一文看盡。

          李開復張亞勤揭秘相識往事

          李開復張亞勤的巔峰對話環節,主要討論了三個方面。

          首先,他們回憶起23年前回國創建微軟亞洲研究院MSRA的事情。

          當時李開復給張亞勤打電話,就“畫了很大的餅”。他們想一同打造中國計算機的黃埔軍校,以此證明給全世界看,中國人也能做最頂級的科研。

          結果就在張亞勤決定回國,到北京第一天就被李開復修理了。

          嗯,理發的理。

          張亞勤回憶到,當時跟沈向洋一同回國,頭發因為很長時間沒打理,他們就被李開復帶去理發了。

          如今回過頭看,當初說要建立個亞洲最牛、全球一流的計算機實驗室這一個目標,在張亞勤看來已經實現,尤其在培養人才這方面。

          而且過程中,也有讓他們感到意外和大受震撼的進展。

          比如李開復舉例,誰能想到后來的AI四小龍的創始團隊,都有微軟亞洲研究院的背景。

          還有像現在頂尖高校、大企業CTO以及一些創業公司,都有特別多當時培養的人才。

          我們感覺特別欣慰,有種桃李滿天下的感覺。

          接著,他們探討了當下最流行議題和技術風向。

          比如元宇宙

          李開復認為,它肯定會到來的,但五年之內不會有特別巨大的公司或應用出現。

          張亞勤則補充,要用開放的心態去看待元宇宙。

          一方面,如果說,元宇宙是真實世界與虛擬世界的融合,但以真實世界為主的話。

          很多公司已經在做了,目前產品形態是技術的一種拓展。

          另一方面,要說元宇宙是完全的虛擬世界,和真實世界沒關系,那可能走得就太遠了一點。現在也有不少炒作,技術也并不成熟,還需要不斷地發展。

          再比如,科學家創業的熱議趨勢。

          兩位老朋友一致認為,科學家創業需要一個企業家伙伴

          張亞勤還補充道,科學家還需要專注。如果決定創業,那就出來做這件事。他認為科學家同時上課做科研,還要管理公司是很困難的。

          最后他們放眼未來,有哪些領域和賽道值得看好。

          張亞勤提及了AI與生物計算和生命科學交叉、無人駕駛和智慧交通,以及IOT。

          而李開復Pick的第一個與張亞勤相同,除此之外還有機器人領域,尤其在工業制造上的應用,以及自然語言理解。

          尤其是自然語言理解,李開復認為它在近幾年的發展跟當年CNN、DNN一樣,正從感知智能迅速邁向認知智能。未來AI一旦超越人類,就能做很多輔助、取代人類的工作。

          而至于自身的未來小目標,張亞勤還是繼續3.0人生——把AIR做起來,李開復則是想用行動證明做高科技的投資回報要比互聯網更高。

          哦對,這當中還有個小插曲。

          當兩位被問到,如果有項超能力——可以復制對方的能力,那會如何選擇。

          李開復首先就說,會復制張亞勤12歲就能讀大學的天才能力。

          而張亞勤,最想復制李開復吃遍美食還不胖”的能力。

          此外,亞勤還說想復制他對未來的洞察,以及可以用簡單的語言把復雜事物表述總結出來的能力。

          李開復和張亞勤的巔峰對話,由量子位總編輯李根主持,在對話環節最后,他表示能夠促成開復和亞勤的這樣一次“老友對談”,是量子位一直以來的愿望——

          不僅是因為兩位大咖今時今日的地位和成就,更是因為他們在23年前作出的回中國的決定,某種程度上來講,奠定了如今智能未來的基礎。

          而且更關鍵的是,開復和亞勤,還都在繼續為產業培育人才、鼓勵創新,是中國智能產業領域當之無愧的兩座高峰。

          清華張亞勤:下個十年是AI與生物制藥融合的大好時機

          實際上,在巔峰對話開始前,清華大學智能科學講席教授、清華智能產業研究院院長張亞勤,還以開場主題演講的形式,分享了他對趨勢——特別是AI+生命科學的判斷。

          清華智能產業研究院AIR于2020年成立,其使命是用人工智能技術賦能產業推動社會進步。

          清華AIR選擇了三個方向作為突破點:智能交通、智慧物聯、智慧醫療。張亞勤這次分享的重點是智慧醫療方向中,人工智能如何賦能生命科學。

          他認為整個信息產業過去三十年最大的突破就是數字化,從開始的內容數字化、企業數字化,到現在進入物理世界的數字化和生物世界的數字化。

          一方面我們的身體從大腦、器官,到細胞、蛋白質、基因、分子都在數字化,另一方面人工智能算法、算力和系統的快速進展讓大量數據有了使用的場所。

          以前新藥研發需要超過十幾年的周期,十億美元的投入, AI正在改變這種狀況。

          新冠疫苗去年年底進入臨床試驗,今年大規模使用,這可能是人類歷史上最快的一次計算機科學包括人工智能加速疫苗開發的例子。

          另外遷移學習用少量原始數據加上動物模型快速發現了對罕見病的藥物,幾何深度學習找出了廣譜、穩定的新冠抗體,對變種株也有效,Swin Transformer用于測序基因里90%的未編碼部分……

          張亞勤總結道,AI和生命科學有很多可合作的地方,能讓生物制藥更快速、精準、安全,更經濟、普惠。

          但同時也有很多壁壘,算法的透明性、可解釋性、隱私安全、倫理等挑戰,以及如何把兩個行業無縫連接起來。

          由此研究院提出了「AI+生命科學破壁計劃」作為前沿研究任務,跨越兩個領域的鴻溝、打破壁壘促進AI與生命科學的深度交叉融合,構建AI+生命科學的研究和技術生態。

          張亞勤看見了生物世界的數字化和AI技術的進展,相信下個十年是生物制藥和人工智能融合的大好時機,也是行業發展的最大的機遇。

          百度吳甜:技術創新持續為產業發展注入新動能

          百度集團副總裁、深度學習技術及應用國家工程實驗室副主任吳甜解讀了技術創新與產業發展的關系。

          根據中國信息通信研究院的數據,2020年我國數字經濟已經達到了39.2萬億元,占GDP總值的38.6%,位居世界第二。未來這個數值的絕對值和相對比例都會持續增加,數字產業化和產業數字化齊頭并進。

          產業發展角度,可以看到產業使用人工智能的場景廣泛且分散,技術與產業的結合越來越深入、專業,未來前景會更大更廣闊。

          技術發展角度,人工智能呈現出明顯的融合創新趨勢,包括軟硬一體融合、跨模態多技術融合、知識與深度學習融合、技術與場景融合。

          雖然底層技術越變越復雜,但所幸能夠通過開源開放的人工智能平臺降低門檻,使AI開發變得越來越容易。

          如金融領域常見的智能合同解析與管理場景,傳統都是靠人工方式從合同中提取三十多個維度信息,效率低,而保險的產品迭代速度又很快,相應的保險條款也在增加和變化,人工識別一份合同需要30分鐘。技術工程師在開發平臺上使用ERNIE訓練了條款智能解析模型,并持續進行迭代優化,部署到保險業務平臺中,提供智能解析能力,對合同文本實現了智能解析,達到通過智能輔助后單份合同解析時長縮短為1分鐘。

          像這樣的變化,在各個行業當中都在發生。

          吳甜總結道,一方面是產業的需求越來越旺盛,越來越多和廣泛,另一方面技術本身也給我們帶來新的想象空間,技術創新持續為產業當中運用人工智能技術注入新的動能,注入新的活力。

          IBM謝東:如何讓技術創新驅動環境智能和企業可持續發展

          IBM副總裁、大中華區首席技術官謝東博士為我們分享「加速科技創新,共贏可持續未來」的議題。

          從全球發展狀況來看,可持續發展是我們共同面對的戰略議題。世界經濟論壇2021年全球風險報告指出,未來十年企業面臨前的三大業務風險都與環境相關。

          在中國雙碳目標下,可持續發展不光是我們所有企業的社會責任,更加已經成為企業必須面對的戰略議題。對于企業應該如何面對這些挑戰,新技術突破會給行業帶來哪些轉變?

          謝東博士從三個維度做了梳理。

          企業治理角度,IBM非常注重可持續發展問題,早在50年前,制定了首個企業環境的政策,2000年提出二氧化碳減排目標;與全球各行業客戶建立可持續發展咨詢委員會。

          當中還為助力中國企業實現碳中和制定四階段戰略建議,包括確保合規、優化流程及供應鏈、重塑業務、引領行業。

          基于環境問題,IBM推出環境智能套件,涵蓋人工智能、數據分析、環境數據分層、混合云、物聯網與區塊鏈。

          在技術平臺助力環境議題和創新的維度,以IBM位于蘇黎世的云上自主化學實驗室RoboRXN為例,全球可以通過網絡直接訪問到實驗室,遠程完成了從文獻檢索到一些科研探索,再到功能驗證各個環節。

          過去兩年,化學實驗室RoboRXN采用的免費AI模型,已經為學生、科學家和實驗者完成了近100萬次反應預測。

          而背后能支撐這一系列環境和可持續發展創新的底層計算技術又是怎樣的?謝東博士提到了最新推出的2nm芯片技術、帶有片內AI加速器的處理器Telum,以及前不久發布的突破127 量子位量子處理器。謝東博士認為,量子計算機規模化商用可能已經在不遠的未來了。

          小冰李笛:AI相比人類創作者,不存在瓶頸期

          小冰公司首席執行官李笛認為,有時候人們會過于高估人工智能在IQ方向的進展,卻低估了人工智能在EQ方面蘊藏的巨大潛力。

          那些出現在人類身邊、與人類共存的「AI being」都應該有自己擅長和不擅長的領域,有自己的性格和觀念,無所不知、無所不能的AI反而是面目不清的。

          在迪拜世博會中國館,正在展出AI畫家夏語冰的一系列水墨畫作品《山水精神》。

          夏語冰除了創作能力也有著自己的面容、口音和創作觀念,與另一位AI畫家山東大哥完全不同。

          李笛指出,如果要賦予AI創造力,它對不同事情的觀念要有一致性,并反映在其所創造的東西上,才能讓人類不感到違和。

          當人工智能習得一定創作能力的時候,和人類創作者區別是什么?

          第一,人類創作到了巔峰之后便開始滑坡,人工智能沒有巔峰,要么是停滯的、要么會繼續向上攀登,時間周期非常久。

          第二,人類在同一時間只能專注地做一件事情,但人工智能是可以高并發的。

          創造力只是小冰框架中的一小部分,最難的是如何賦予AI有趣的靈魂,真正和人類交流。

          李笛看到人工智能在EQ方面蘊藏的巨大潛力,他相信我們這一代是與多樣的人工智能生活在一起的第一代人類。

          Rokid祝銘明:元宇宙更應專注虛實融合

          Rokid創始人CEO祝銘明則在大會上探討了AR智能眼鏡行業的應用落地探索。

          當前大家談元宇宙,很多人談的是創想與未來,Rokid關注的是技術落地能力,主要有5個方面:

          感知——理解——協同——展現(光學技術、圖形引擎)——數字資產/內容(創作、生產工具)

          祝銘明介紹,Rokid是一家產品平臺型公司,除了上述五種能力,還會考慮一些載體去做和大家進行交互,也根據自己思考分成了四個象限。

          橫軸代表以穿戴性、佩戴性為出發點去衡量,從專用場景到日常佩戴(從左到右)。

          縱軸是以展現能力為一個衡量點去思考,從內容屬性到工作屬性(從上到下)。

          第一層,感知能力,如半導體、傳感器等技術。

          第二層,關注在感知基礎上如何理解世界,理解周邊的環境、理解人、理解事。

          第三層為協同,深度思考人和人、人和事物之間的協同關系,但不是創造虛擬世界,而是融合真實世界和數字世界。

          第四層,視覺和感官層的展現能力,背后涉及光學、圖形引擎、算法、空間引擎等技術。

          最后,為數字資產(數字內容生產)。包括創作工具、生產工具、管理、安全等方面的能力。

          過程中,祝銘明還強調,Rokid做人機交互有著不同的階段,從最早指令型的人機交互,到后面圖形化的所見即所得的人機交互,對人類越來越友好。

          在分享的最后,他提出了自己對于元宇宙的思考。

          如果元宇宙是一種發展方向,那我們覺得元宇宙不應該是局限于虛擬世界,如何將人與真實世界和虛擬世界做一個完整的融合,不應該割裂開,這是我們一直在主導的事情。

          他看到了人機交互的巨大潛力,他相信在未來,真實世界跟數字世界將進行融合而非割裂。

          亞信科技歐陽曄:5G把AI 能力投送到邊緣


          亞信科技首席技術官、高級副總裁歐陽曄帶來了《5G網絡助推邊緣AI》的主題演講。

          以2006年AI第三次發展浪潮開始作為節點到現在的15年間,通信領域與AI相關的學術成果發表數量是之前15年的6.42倍。同時隨著5G技術與業務的發展,云端智能需向邊緣遷移。

          通信技術作為數字化轉型的基礎設施,該如何利用5G通信技術把AI能力投送到千行百業的邊緣觸點?

          歐陽曄博士介紹了5G網絡投送AI能力到達邊緣的三種模式:

          • 5G網絡切片,可以理解成在現有的公有網絡里構建一層專用的高速隧道。
          • 5G獨立專網,企業搭建的私有網絡。
          • 5G混合專網,專網與公網共享基站的模式。

          AI能力投送到邊緣后并不是就能直接應用到各種to B和to C場景,而是通過第五代移動通信邊緣計算平臺承載多種通用目的技術(如AI,數字孿生,數據治理與AIoT等)構建云邊端協同整體方案。

          隨后歐陽曄介紹了基于五代移動通信邊緣計算平臺的智慧電廠、智慧工地和智慧園區3個典型場景案例。

          歐陽曄指出通信和AI兩個領域的發展相關性將越來越強,他相信在未來,應用層廠家、通信基礎設施廠家以及運營商合作伙伴要共同努力,共同觸及通信人工智能未來十年的發展。

          京東何曉冬:對話本質上是博弈與決策,語言只是一種表現形式

          京東集團副總裁、京東探索研究院常務副院長何曉冬則分享了多模態智能人機交互技術在復雜場景中的進化,以及技術落地給人類創造價值。

          提到人工智能,往往會想到語音識別,圖像識別、人臉識別、甚至機器翻譯。

          對話智能是種什么智能?某種程度上講是一種融合性智能,前面提到單點基礎技術都被融合在其中。

          簡單說,對話智能就是希望打造一個機器,它能夠自如像人一樣跟你對話交流溝通關懷,完成任務。

          表現上看,它是種非常自然地交互方式;從技術上看,它需要感知智能、情感智能、認知智能、多輪對話管理。

          何曉冬認為,對話即決策,本質上來說對話本質上是博弈與決策,語言只是一種表現形式。

          接著,何曉冬介紹了在京東是如何迭代技術、讓這項技術為更多用戶所用、創造更多的價值。

          簡單來說,兩種模式并行:打造前沿的技術能力,同時把前沿的技術推向千行百業應用落地。

          剛剛過去的雙十一,何曉冬團隊通過智能人機對話系統打造的京東智能客服言犀,累計服務了超過7.4億咨詢量、16.5萬的第三方商家,智能物流預約外呼超過了193萬通電話,完成2.1億次的質量檢測,在整個京東的售前、售中、售后、物流各個環節實現了客服服務全鏈路的場景智能化。

          大會現場何博士還給我們演示了智能人機對話系統服務成都顧客的真實案例~

          而為了讓機器人做得更好,京東還打造了五個維度的服務評價質量指數,來評價機器人和人之間的差距,展示京東在智能人機對話領域深刻的沉淀。

          除了服務京東本身以外,他們的多模態智能人機交互技術還運用到更多行業當中去,比如政府的政務熱線、金融行業的業務客服等。

          展望未來五年,人工智能的三大支柱數據、算力、算法,都會得到進一步升級場景、系統、算力。

          數據升級成持續運作的“活”場景數據;單點的算法進一步提升至綜合性的AI系統,包括多算法互相協同、聯合優化,這樣才能打造真正端到端、高價值的AI系統。

          商湯楊帆:AI算法下一個時代是端到端系統化整合

          商湯科技聯合創始人、商湯集團副總裁楊帆認為,賦能產業升級是AI的核心價值所在。

          今天在各行各業都有對AI的剛需存在。

          如工業檢測分析的痛點是效率低、漏檢率高和標準不統一、檢測人員水平差異大等。城市管理分析中事故的偶發性高、分散,需要大量人力投入。

          楊帆說,眼下AI企業會越來越面臨一種「幸福的煩惱」。

          幸福之處在于剛需大量存在,煩惱之處在于剛需碎片化、場景多樣化,AI企業提供技術創新的成本,包括邊際成本比較高,造成了AI產業進一步發展面臨的供需匹配失調的問題。

          要解決這些煩惱一方面需要有通用能力的基礎設施為人工智能產業創新提供支撐,另一方面需要跨組織之間的聯合和協作。

          楊帆從在商湯做算法的經歷出發,總結出算法的三個時代。

          第一個時代像手工業,非常依賴個體科學家的個人水平。

          第二個時代就是過去這5年,像工業化流水線,能夠用更多系統把算法創造的各個環節整合打通,持續的規模化的生產技術創新。

          下一個時代該是什么?楊帆認為技術創新會走向更加通用、低成本高效,就像工業流水線趨勢是自動化智能化。

          從底層基礎設施,到硬件,再到軟件和上游應用,形成端到端系統化模式,把各個環節進行更加標準化的定義以及有機組合。

          端到端整合可以帶來更高的安全性以及更低的網絡時延,同時把算法打造成像樂高積木塊一樣,提供給產業內的大家共同去打造有價值的應用。

          楊帆看到了行業剛需當下沒有被很好的滿足,他相信平臺化、規模化、低成本高效率的工具體系,會讓整個產業技術創新走得更快。

          思謀劉樞:AI技術正在成為一種新型生產要素

          思謀科技聯合創始人兼技術負責人劉樞在大會分享了思謀科技如何用AI推動制造業數字化智能化轉型。

          人工智能在推動經濟發展的同時,也在創造虛擬勞動力,去做人類不想做、做不好、不能做的事情,同時當人工智能在很多行業落地的時候,可以拉動其上下游協同發展和創新。

          因此作為兩年即長成獨角獸的思謀科技,認為“人工智能技術正在成為一種新的生產要素”。

          埃森哲曾預測到2035年,人工智能可以將年經濟增長率額外提升1.6%,人工智能作為單獨技術將額外帶來8千億美金增長,而如果作為生產要素去評估,將帶來6萬億美金的規模增長。

          再來看制造業的發展,總共經歷了三個階段:自動化-信息化-智能化,如今智能制造蘊含著巨大發展機遇。

          智能制造,關鍵在于智能——即讓制造擁有大腦,自動化只是手臂,把決策變為現實。但實際落地過程中,思謀科技遇到了些有意思的問題,這與熟悉的自然場景有許多不同。

          首先,數據極度短缺。在工業場景里面,很多時候每一種缺陷的圖片數量都達不到10。

          第二,工業驗收要求非常高。以手機為例,如果要求手機成品良率99%,假設一臺手機含200個零件,那么每個零件良率都需達到99.99%。

          第三,被檢形態非常多。常用器件就可能有成百上千種不同的形狀。

          第四,缺陷難以區分。

          劉樞認為,只有當系統可以自動實現算法組合和部署,人類只需要少量定制化算法設置的時候,才有可能實現AI跨領域規模產業化。

          如果沒有自動實現算法組合和部署的系統,在高端制造業實現AI全面產業化會非常艱難。

          以智能手機為例,零件供應商平均來講有400個,每個供應商有五個制程,每個制程又有15條產線,如果一條產線都做一個模型,大概要做3萬個模型。

          再放眼全行業前五的品牌,每個品牌6款產品,則需要90萬個不同的算法模型,這其中還不算第二年、第三年的軟硬件升級迭代。

          為了達到這一目標,思謀科技研發了AI算法平臺SMAP,以及沉淀了AI Know-How的DataFlow系統。

          最后,劉樞還分享了智能制造的核心原則:普適性,計算為先和永不間斷的學習。

          當AI系統設計能夠自動化,當AI部署和運營能夠自動化的時候,就一定能夠實現新一代智能產業的變革。

          數牘科技蔡超超:隱私計算,構建下一代數據流通底層的關鍵設施

          數牘科技聯合創始人兼CTO蔡超超分享的主題是《隱私計算構建下一代數據流通底層的關鍵設施》。

          剛才我們提到智能駕駛場景,就和隱私計算有很大的相關性。

          智能汽車在運行過程中產生大量圖片、音頻甚至位置數據,都涉及到用戶的隱私。這些數據的高效開發利用需要在保護數據安全的情況下進行,需要用到隱私計算。

          隱私計算是一種在數據不可見的前提下,讓信息進行價值流通的工程和技術體系,涉及多方安全計算,聯邦學習、可信執行環境、差分隱私、同態加密、區塊鏈等多種技術。

          蔡超超同時認為隱私計算體系不是一個單一的系統,它其實是一個網絡,一個底層平臺,包含了不同的參與方。

          每個參與方的主體可能是人、是車或其他設備,這些主體都會有自己的ID,比如身份證、電話號碼、設備號,在數據合作之前需要有共同的語言把ID有效統一對齊起來,才能進行安全的數據協作。

          基于隱私計算的ID系統可以做到匿名化、原始ID和敏感信息不可追溯、不可還原。

          接下來,讓多方在不交換原始數據的前提下進行安全合規的數據協作,應用于反欺詐、反洗錢、精準營銷、聯合風控等一系列場景。

          蔡超超看到了有數據價值交換的地方就有隱私計算的需求,他相信隱私計算平臺發展過程中需要注重安全可靠性、有完整的數據科學應用體系以及工業級落地能力。

          智駕周圣硯:以規模化迎接智能駕駛平權時代

          智駕科技創始人兼CEO周圣硯在大會上分享了智駕視角下自動駕駛產業以及今后發展是如何的。

          一開場,周圣硯就舉了一個小例子:如果問消費者,什么品牌汽車做的比較好,消費者能輕易列出答案。但如果問自動駕駛有哪些比較好的公司,可能大多數消費者都沒辦法答出。

          為什么會有這樣的現象?如果回顧互聯網行業的發展,就會發現它之所以能蓬勃發展,是因為覆蓋了最廣大用戶群體。

          回顧過去幾年自動駕駛的發展一直非常曲折,原因在于大家一直在技術路徑和商業模式上產生強烈的爭議。如今這些爭議依舊存在,但同時也確實感受到自動駕駛正在實現并產生社會的正向價值

          SAE把自動駕駛從工程學的角度分了L0-L5不同駕駛等級,智駕科技MAXIEYE今天從解決問題的角度重新分解自動駕駛等級。

          首先,即第一個等級,需要解決的是安全問題,比如車輛的緊急制動系統。

          第二個等級,駕駛過程中的舒適性問題,比如高速公路實現的全速巡航系統。

          第三個等級,解決出行效率問題。智駕科技MAXIEYE認為在結構化道路,比如城市道路和高速公路,可以實現點到點的自動駕駛功能。

          第四個等級,優化交通能源的問題,比如干線無人物流。前三個等級叫做人機共駕,最后一個等級才叫做無人駕駛。

          最后,他希望與行業一起迎接智能駕駛科技平權時代的到來。

          從市場維度,產品全面下探最廣泛的5-15萬元車型,將覆蓋最廣大的用戶群體;從消費者維度,提供消費者用得起愿意用的智能駕駛產品;從產業鏈維度,全行業開放共創,建立行業共識和技術協同,全產業鏈去共同打造智能駕駛科技平權時代。

          周圣硯看到自動駕駛需要覆蓋更廣大用戶群體,他相信未來AI將以數據驅動方式助力智能駕駛系統越用越聰明。

          自動駕駛圓桌論壇:量產、安全,變局時刻

          大會的最后階段,自動駕駛行業大佬們圍繞「量產」展開了激烈討論。

          先來介紹一下各位嘉賓:

          騰訊交通平臺部總經理、自動駕駛總經理蘇奎峰

          過去一年騰訊從自動駕駛測試工具鏈,以及智能聯網示范區、智慧高速等車路協同解決方案兩個方面助力產業發展。

          無人駕駛公司馭勢科技聯合創始人、首席系統架構師彭進展

          馭勢科技開展了無人車在多個場景的商業化運營,擁有在機場、工廠等場景幾百臺車7x24小時、365天持續不斷的運營能力。

          無人卡車公司主線科技CEO張天雷

          主線科技專注于自動駕駛卡車,在幾個港口物流樞紐還有京津高速、京滬高速上運行的車輛規模有150輛車左右,每天都在持續地運行。

          那么開始第一個話題,2021年怎么就成了自動駕駛量產集中的一年?

          首先三位嘉賓都認為政策很關鍵,三個團隊創業之初都獲得了資金支持,來自國家自然科學基金。

          另外今年從北上廣深到武漢、長沙、無錫再到衡陽,無論一線還是二三線城市都開始積極推動無人駕駛落地。

          張天雷提出第二個因素:場景

          張天雷覺得物流場景尤其是封閉的完全無人的,還有高速以及一些城區限定區域內的場景,從今年開始包括到明年年底很有可能有很多批量的應用出來。

          彭進展的角度是技術進展,無人駕駛如果不能把安全員拿掉,就體現不出真正的價值。

          只有真正把安全員拿掉,你的客戶和合作伙伴才會相信這件事真的能成功。

          最后蘇奎峰總結發言,政策、場景和技術全都交匯在今年這一點,無人駕駛量產終于到來。

          第二個話題:量產之后,大眾都「看見」了自動駕駛,未來行業會面臨哪些新的挑戰?

          雖然問題比較寬泛,不過三位的表達不約而同的集中在了安全這個點。

          蘇奎峰提到,只要自動駕駛的量產規模大了,原本的一些小概率事件也會變成常發事件,這不代表技術不好,但確實有許多長尾的問題需要預見和克服。

          他強調:

          我們在安全性、穩定性上要有敬畏心。

          彭進展認為無人駕駛在安全上的優勢在于實時性,實時監控反映,實時通過AI去控制。

          雖然理論上可以計算出無人駕駛事故概率就是遠遠低于人類駕駛,但實際中還需要做進一步驗證。

          每天都會發生人為因素引起的交通事故,但對于大眾來說并不算什么新聞。期待有一天,大眾對自動駕駛出事故也有一個平常的心態。

          張天雷則指出沒有一個系統能夠百分之百的保證總是正常運行,我們要做的是把出錯的代價降到最小,核心的問題是不要有人員的傷亡。

          在任何時候,自動駕駛的安全性永遠排在第一位。為了系統的安全性,付出再多代價也是需要的。

          圓桌討論的最后一部分,是每人分享一件行業中最感到意外的事。

          蘇奎峰:

          到頭來是新能源加速了自動駕駛落地。

          彭進展:

          震撼最大的是行業真的做到把安全員拿掉了。

          張天雷:

          特斯拉投入巨大精力做數據驅動,造了世界上排行第五的超算機群來訓練模型,這是中小型國家都做不到的。

          從那時開始,大家明白了一個道理,自動駕駛是個軍備競賽。

          因為看見,所以相信

          過去的一年,是復雜變化的一年。

          但前沿科技始終是社會發展的重要動力,也蘊藏著無比的機遇。AI大模型、自動駕駛、生物計算等領域正在加速改變世界,前沿計算、新型儲能等方向新探索不斷涌現。

          與此同時,前沿技術的落地也愈發如火如荼。新技術、新產品讓我們的生活越來越好,越來越有趣。

          不過一切也并非一帆風順。

          量子位創始人兼CEO孟鴻表示,前沿科技的發展總是起起伏伏,發展的范式會改變,上升的道路會改變,但前進的趨勢不會改變。

          今年到場的來賓,都是因為對前沿科技有一份堅定的相信,進而選擇在這個方向上不斷推動世界前進。

          整場大會下來可以看到,他們今年交出的商業化落地答卷,在更深入現實的地方被交出。

          而這也只是今年諸多技術創新案例中的一隅。

          作為人工智能年度最佳落地參考,「2021人工智能年度評選」結果也已揭曉。在過去2個月時間里,共有數百家科技企業、機構和個人報名參與評選。

          最終評選出50大領航企業、20大最具價值創業公司、30大創業領袖、20大技術領袖、10大最佳產品以及10大最佳解決方案等在內人工智能領域年度獎項。

          這些無一不在印證本次MEET智能未來大會主題:因為看見,所以相信。

          希望讓更多人看到前沿科技的進展和落地,讓更多人進一步相信前沿科技背后蘊藏的巨大價值。

          那么這一年,你看見了什么?從而又相信著什么?

          Ps,也許量子位最新發布的「2021人工智能年度評選」,可以給你參考,鏈接在此:https://mp.weixin.qq.com/s/E3wcXr3PA0uZAZ1N-lgThg。

          Pps,如果想回顧精彩內容,回放鏈接在此!
          微吼:http://live.vhall.com/127740714
          微博:https://weibo.com/l/wblive/p/show/1022:2321324707747747987514
          百家號:https://live.baidu.com/m/media/multipage/liveshow/index.html?room_id=5008651533
          CSDN:https://live.csdn.net/room/wl5875/tVtNmdeX
          斗魚:https://v.douyu.com/show/85BAvqrrERB7G4Lm?ap=1

          — 完 —

          量子位 QbitAI · 頭條號簽約

          關注我們,第一時間獲知前沿科技動態



          是現代量子化學的奠基人,也是分子生物學研究的開拓者之一。憑借對量子力學原理和分子結構的深刻理解,少壯得志、堪稱天才的鮑林以他非凡的刪繁就簡和構建模型的能力,一次次在化學和生物學難題上攻城略地,風光無兩。然而盛名之后的他,卻因執迷維生素C神話而成為醫學史上的笑談,其人生的最后25年令人唏噓不已……


          撰文 ∣ 何笑松(加州大學戴維斯醫學院退休教授)


          萊納斯·鮑林(Linus Pauling)出生于1901年,是20世紀最偉大的化學家之一,因其對化學鍵及分子結構的一系列重要研究成果獲得1954年的諾貝爾化學獎。鮑林也是20世紀五、六十年代最著名的和平主義活動家,他堅決反對核武器及一切形式的戰爭,并因此在1963年獲得諾貝爾和平獎。鮑林因此成為有史以來唯一單獨獲得兩項諾貝爾獎的個人。

          但從1960年代開始,頭戴兩頂諾獎桂冠、正值事業和名譽巔峰期的鮑林卻一步一步地成為維生素C的最有力推手。這一轉變是如何發生的?

          維生素C神話的第一次登場


          鮑林的維生素情結始于1941年,當時年僅40歲的鮑林得了腎病。在一位著名醫生的建議下,鮑林接受了當時少有人用的低蛋白無鹽飲食療法,輔以維生素補充劑,病情得到控制。這一親身經歷,為鮑林以維生素治病的觀念打下了根深蒂固的基礎。

          1950年代中期,作為當代最偉大化學家之一的鮑林,逐漸形成了一套關于人類健康的綜合理論。他相信人的生命可被視為無數化學反應的總和,其中最重要的是酶催化的產生能量的反應,導致細胞繁殖和遺傳復制的反應,大腦和神經中的電化學反應,以及抗原-抗體反應。如果這一切反應都順利進行,就意味著健康;哪一項反應受阻或者停止了,就意味著疾病。要想實現理想的健康狀態,就必須使所有的化學反應都在最佳狀態下運行,也就是所有的化學分子,包括營養成分、催化劑及反應產物,都處于適當的平衡狀態。鮑林為這種平衡造出一個詞匯“正分子”,意指“正確的分子,正確的數量”,以此為基礎的醫學就是“正分子醫學”,它著眼于將病人所需要的重要分子補充到最佳濃度,以消除疾病。

          1966年3月的一天,65歲的鮑林在紐約接受了一項科學成就獎。他在頒獎儀式上發表獲獎感言時,提到希望自己再活25年,以便看到幾項科學研究的結果。回到加州后,鮑林收到一封信,來自一個名叫斯通(Irwin Stone)的陌生人。斯通參加了紐約的頒獎儀式,聽到鮑林的愿望,于是他寫信建議鮑林像他一樣,每天服用3000毫克(3克)維生素C,這樣不僅再活25年不成問題,而且可能還要長的多。

          被鮑林稱為“生物化學家”的斯通是何許人?他在美國洛杉磯的一所脊椎推拿療法學院學過兩年化學,后來從加州一所名為“唐斯巴赫大學”,未經美國聯邦政府教育部認證的野雞函授大學得到一個博士學位。斯通從來沒有發表過任何一篇科研論文,而著作等身的鮑林居然聽信了他的建議,開始服用大劑量維生素C,從每天500毫克,1克,直到18克,超過了美國食品和藥品管理局(FDA)推薦的成年人每日攝入量的200倍。鮑林發現這果然有效,他宣稱從來沒有自我感覺如此健康,如此精力旺盛,連年年令他備受折磨的感冒也不太發生了。1969年,鮑林開始通過媒體宣傳,醫生應該多多鼓勵公眾服用大劑量維生素C。

          針對鮑林的言論,有一位協助FDA制定維生素C推薦攝入量的臨床營養學家致信鮑林,要求他提供證據。鮑林的答復是在1971年出版的《維生素C與普通感冒》,書中匯集了他找到的關于維生素C的健康效應的研究結果,聲稱對于大多數人,每天服用1克維生素C,可以將感冒的發病率降低45%;而對有些人來說,劑量可能還要更大。一旦感冒的癥狀出現,就應該每小時服用半克至1克維生素C,連服幾個小時;如果這樣的劑量還不見效,那就再加大到每天4至10克[1]

          鮑林的這本新書立即登上了全美暢銷書排行榜,激起了巨大反響。幾年不到,就有四分之一的美國人遵從鮑林的建議,服用巨量維生素C。1976年,這本書再版后改名為《維生素C與普通感冒及流感》[2],書中推薦的劑量更高了。

          不僅如此,鮑林在書中還建議為了保持“最佳健康狀態”,應對感染及其它壓力,多數人每天應服用至少2300毫克維生素C。在他后來出版的又一本面向大眾的暢銷書《怎樣活得更長更好》[3]中,鮑林聲稱由于不同個體之間生物化學上的差異巨大,維生素C的每日最佳攝入量可以少至250毫克,多到20克以上,這樣才能達到許多哺乳動物肝臟內自行合成后釋放到血液中的維生素C 的水平。這是多少維生素C?以山羊為例,一只健康的成年山羊每天能合成13克維生素C,遭到壓力時還要高得多!

          鮑林對他的理論身體力行,自稱長年每天服用12克維生素C,出現感冒癥狀時更是增加到40克!盡管主流醫學界的絕大多數醫生和營養師反對鮑林的理論,并且指出長期服用巨量維生素C可能引起慢性腹瀉及腎結石,千千萬萬的美國人還是狂熱地追隨鮑林的倡議,以身試藥。

          維生素C與感冒

          現代醫學的主流是循證醫學,它強調任何醫療決策應該以來自科學研究的最佳證據為基礎,同時結合醫生的個人臨床實踐經驗,并且考慮病人的價值觀和愿望。鮑林宣稱的巨量維生素C對于預防及治療感冒的奇效,究竟有何科學證據?

          任何科學證據的確立,必須服從一套嚴格的規則,也就是科學方法。簡單地說,這是一套精心設計、可以區分因果關系和巧合關系的邏輯系統,利用它對有效的實驗進行分析,才能為特定的醫學問題提供科學答案。必須強調的是,并非所有的實驗都符合條件。有效的實驗必須是設計正確、數據采集可靠、統計分析無誤、結果解釋合理。有效實驗的一個重要標志是能被其他人重復進行,而且得到相同結果。

          關于維生素C與感冒的關系,關鍵的問題是兩個:1. 大劑量維生素C能否預防感冒發生?2. 大劑量維生素C能否減輕感冒癥狀,縮短感冒病程?從1930年代維生素C被發現,特別是實現工業化生產后,就有醫學研究人員多次研究過它對感冒的作用。大多數研究的結論是補充維生素C不能預防感冒;對于治療感冒,維生素C的作用充其量是略微減輕癥狀,而且并不需要鮑林提倡的高劑量[4]。鮑林的《維生素C與普通感冒》一書出版后,由于它的巨大影響,同時出于對鮑林的尊重,又有美國、加拿大及荷蘭的研究人員進行了一系列研究,分別試驗了不同劑量維生素C對于預防和治療感冒的作用,結論還是毫無效果。

          可是鮑林堅定地認為,根據他對同樣的試驗結果作出的不同解釋,他是正確的,其他人都錯了。他還提出每個人可以用如下方法自行確定合適的維生素C劑量:如果每天吃1克,一冬天得了兩次或者三次感冒,那么就應該加大劑量試試;如果感冒的次數少于預期,那么就可以相信是維生素C起了作用。

          遺憾的是,這距離真正的科學方法何止十萬八千里。不妨試想以下幾種可能發生的情況:

          其一,你記錯了自己感冒的次數,這將造成數據采集的錯誤。

          其二,你去年在醫院工作,得過三次感冒。今年退休在家,同時開始吃維生素C,只得了一次感冒。你相信這是因為吃維生素C預防了感冒,但更大的可能性是由于環境變化,你被感冒病毒感染的機會少了。如果是這樣的話,你吞下的維生素C和少患感冒就只是巧合。

          其三,你吃著維生素C,同時得了一場輕微的感冒。由于你對維生素C的信仰如此堅定,因此下意識地決定不予理會,這就是心理作用造成的安慰劑效應。

          科學實驗的設計必須能夠避免這些可能的誤差。為了防止記憶錯誤,對實驗對象必須密切跟蹤隨訪。為了消除巧合的影響,實驗對象的數目要足夠大,隨訪期要足夠長。為了避免安慰劑效應,實驗必須采用雙盲法。具體做法是,募集一批受試者,隨機分派到實驗組和對照組,以確保兩組人的遺傳背景、生活環境等情況盡可能相似。每一個受試者本人及其家人,以及為受試者提供試驗藥物的研究人員,都不知道受試者被分在哪一組。有些研究甚至只用同卵雙胞胎作為受試者,將其中一人分入實驗組,另一人分到對照組。尤其是同卵雙胞胎兒童,不僅遺傳基因完全相同,而且通常生活于同一家庭環境,對于臨床醫學實驗的價值更高。研究人員給實驗組每天服用不同劑量的維生素C,對照組服用外觀、味道等與維生素C相似的安慰劑,然后跟蹤觀察一段時間,比較兩組的流感發病率和發病后的癥狀嚴重程度和病程長短。

          感冒臨床實驗的一種做法是直接給自愿受試者接種感冒病毒。這種策略的好處是所有的受試者都接觸到相同的感冒病毒,發病率高而且病情較為一致,所需要的受試者人數較少。1967年和1973年,先后有研究人員進行了這樣的實驗,給實驗組每人每天服用3克維生素C,對照組服用安慰劑,所有受試者在鼻腔接種感冒病毒。結果發現,兩組所有的人都得了感冒,嚴重程度沒有差別。

          另一種策略是觀察自然發生的感冒病例。這樣的研究在各國進行過多次,每次涉及的受試者少則幾百人,多則幾千人。結果如何?沒有一次試驗發現維生素C能顯著降低總的感冒發病率。有些試驗發現維生素C的確能略微減輕癥狀,縮短病程(例如從平均5.8天縮短到5.5天),問題是這樣幾個小時的差別有什么實際意義嗎?

          1975年發表的一項研究結果十分有趣,值得一提[5]。這次實驗歷時9個月,一共有三百多名受試者參加,都是美國國立衛生研究院(NIH)的工作人員。受試者被隨機分為四組:第一組自始至終每天服用安慰劑;第二組在感冒發生前服用安慰劑,發生感冒后每天服用3克維生素C;第三組在感冒發生前每天服用3克維生素C,發生感冒后改為安慰劑;第四組在感冒發生前后每天分別服用3克和6克維生素C。研究從九月份開始,到次年五月份結束,包括了感冒高發的秋、冬、春三季。所有受試者都被告知這是一項采用雙盲對照法的臨床試驗,目的是研究維生素C對預防和治療感冒的作用,并且簽署了知情同意書。

          這次實驗的設計百密一疏,出了一個紕漏:研究人員為了趕在秋季到來時開始實驗,沒有把用膠囊封裝的安慰劑的味道調成和維生素C一樣的酸味。在研究過程中,陸續有一些受試者中途退出,尤其是服用安慰劑的對照組,退出的比例特別高。研究人員對此頓生疑竇,于是在9個月的研究結束后進行了一項問卷調查,發現大約一半的受試者禁不住好奇心的誘惑,打開膠囊,憑著藥粉的味道,正確地猜出所吃的是維生素C還是安慰劑。分到安慰劑對照組的一些受試者覺得自己得不到服用維生素C的好處,干脆中途打了退堂鼓。

          由于有一半受試者不符合雙盲法的要求,研究人員只能將猜出自己吃了什么藥的受試對象挑出來,單獨進行分析。得到的結果令人吃驚:不知道自己分在哪一組、也就是符合實驗設計的雙盲法的受試對象,得了感冒后如果服用安慰劑,平均病程是6.3天,如果服用維生素C,平均病程是6.7天,表明維生素C對縮短病程無效。而那些猜出自己分在哪一組的受試者,得了感冒后如果服用安慰劑,平均病程是8.6天,如果服用維C,平均病程只有4.7天。表面看來,似乎維生素C將病程縮短了3.9天。但是如果將知道自己吃了什么的受試者與對此不知情的受試者比較,如果吃的是維生素C,前者的平均病程比后者短了2天;如果吃的是安慰劑,前者的平均病程比后者長了2.3天!這一結果歪打正著地表現了安慰劑效應的巨大影響:如果你相信吃下去的東西——維生素或者其它補品——有益健康,你就可能感覺它的確有效;如果你相信自己吃的是毫無治療作用的安慰劑,你甚至可能感覺病情變得更糟(稱為“反安慰劑效應”),哪怕藥物的實際效果,無論是維生素C的正面效果還是安慰劑的負面效果,根本就不存在!

          1986年,澳大利亞悉尼大學的教授特拉斯韋(Truswell AS)在《新英格蘭醫學雜志》發文,回顧總結了自1970年以來進行的22次關于維生素C與感冒的隨機雙盲法臨床研究結果。有12項研究發現維生素C對預防感冒發生、減輕癥狀、縮短病程無效。5項研究發現維生素C對預防沒有作用,對減輕癥狀有輕微作用,但在統計學上的差別不顯著。其余5項研究發現維生素C沒有預防作用,但可以縮短感冒病程,雖然程度有限但在統計學上的差別是顯著的。特拉斯韋教授的結論是:“維生素C對于預防感冒顯然沒有作用。”他同時承認,“有一些證據表明,維生素C對治療感冒有微弱的效果,但是……每天250毫克與1000毫克或者4000毫克的效果是一樣的。”[6]250毫克維生素C是什么概念?兩杯橙汁中所含維C就有那么多。如果只是想用維生素C來減輕感冒癥狀,犯得著冒著腹瀉和其它嚴重副作用的風險,遵照鮑林的指示每天吞下幾克維生素C藥片嗎?

          但是鮑林認為,巨量維生素不僅對感冒有奇效,還能治療癌癥。

          維生素C與癌癥

          1970年代,鮑林與一名英國腫瘤外科醫生卡梅隆(Ewan Cameron)合作,研究靜脈注射或者口服巨量維生素C對癌癥的治療作用。二人在1976年和1978年發表了兩篇論文[7, 8],報告了在100名晚期癌癥病人中的試驗結果:接受每天10克巨量維生素C治療后,病人的平均存活期是1000名未服用維生素C病人的3至4倍。兩篇論文都發表在《美國科學院院報》。這是一份影響因子很高的學術期刊,但通常并不刊登有關臨床醫學試驗的論文,而且有時受人詬病的一點是,科學院院士本人在《院報》上發表的有些論文,沒有經過和非院士作者的論文同樣嚴格的同行審稿過程。

          除了治療晚期癌癥,鮑林還提出,服用維生素C可以預防癌癥。1979年,他在一篇文章中宣稱“我目前的估計是,從預防性地服用維生素C做起,單靠維生素C就可以把癌癥的發病率和死亡率都降低75%。”[9]

          NIH 癌癥研究所的癌癥治療臨床試驗分部主任杜伊斯(William DeWys)檢查了鮑林和卡梅隆的實驗設計,發現存在嚴重的缺陷[10]。維生素C治療組完全由卡梅隆的病人構成,對照組則是其他醫生的病人,這兩組病人的選擇標準不一致,所以也就沒有可比性。實驗組的病人存活期長,很可能是由于這組病人在實驗開始前的病情就比對照組輕。

          為了驗證鮑林和卡梅隆所發表的結果,美國梅奧醫學中心在1978年進行了一項前瞻性雙盲對照試驗, 受試者為晚期肺癌或消化道癌癥患者,所有病人都經過腫瘤組織活檢,證實其病情已經不再適合任何手術、化療或放療。受試者被隨機分為兩組,實驗組每天口服10克維生素C,對照組口服味道和維生素C相似的安慰劑。試驗結果于1979年以“高劑量維生素C療法對晚期癌癥無效”為題,在《新英格蘭醫學雜志》發表,文中報告實驗組和對照組的平均存活期都是7周左右,存活最久的一個病人來自對照組[11]

          梅奧中心的研究結果發表后,鮑林投書《新英格蘭醫學雜志》,聲稱梅奧團隊的研究對象都接受過化療,免疫功能已經受損,因此不能從維生素C療法獲益。盡管梅奧團隊先前已經做過研究,知道所用的化療對免疫功能的影響并不嚴重,但他們對鮑林的批評,以及其他研究人員提出的建議還是認真對待,又進行了兩次試驗,其中一次所用的受試者沒有接受過任何化療[12, 13]。前后三次試驗一共包括三百多名病人,三次試驗的結果一樣,實驗組和對照組的平均存活期沒有顯著差別,高劑量維生素C療法對晚期癌癥無效。

          可是此時的鮑林已經接受不了任何與他的觀點不一致的研究結果,哪怕這樣的結果來自他最信任的助手。

          1973年,鮑林在北加州斯坦福大學附近創建了“正分子醫學研究所”,自任所長兼董事會主席,他的弟子羅賓遜(Arthur Robinson)任副所長。羅賓遜博士是鮑林在加州大學圣迭戈分校任訪問教授時物色到的一名優秀學生,后來長期擔任鮑林的助理,輔佐他的研究工作。研究所成立一年以后,改名為“鮑林科學及醫學研究所”,羅賓遜成為正所長。研究所的主要課題就是為鮑林的維生素C理論提供實驗證據。

          1977年,羅賓遜用小鼠進行了一項實驗,研究維生素C對癌癥的作用。所用的是一種特別的小鼠,沒有毛發,皮膚裸露,受紫外線照射后容易誘發皮膚癌。他給一半小鼠喂食大劑量維生素C,按體重換算相當于人類的每天5至10克,另一半不喂維C,作為對照。結果發現,維C不僅沒有降低癌癥發病率,反而使皮膚癌的發病率提高了一倍!不僅如此,對于已經形成的腫瘤,每日相當于1至5克人類劑量的維C可以促進,而不是抑制腫瘤生長,只有將維C的劑量加大到相當于每天100克的人類劑量時,才能抑制腫瘤的生長,而這樣的劑量已經接近維C對小鼠的致死劑量了!

          羅賓遜知道鮑林夫婦二人長年服用巨量維生素C,這不由得令他擔憂。豈料鮑林拒絕承認他的數據,而且不顧羅賓遜已經追隨他16年的情誼,下令董事會將羅賓遜解雇,他的實驗小鼠被殺死,實驗記錄被封存,其中一部分被銷毀。鮑林還公開宣稱羅賓遜的研究工作不夠專業,數據不可靠。羅賓遜忍無可忍,一紙訴狀將鮑林和他的研究所告上法庭。1983年,訴案以庭外和解告終,羅賓遜得到57.5萬美元的賠償,其中42.5萬作為他所遭口頭及書面誹謗的補償[14]

          維生素C與其它一些維生素之所以是維持我們身體健康所必需的營養成分,是由于它們除了具有協助細胞能量代謝的輔酶作用外,還有抗氧化劑的作用。吃進體內的食物在細胞內通過氧化反應燃燒后才能產生能量。其它一些進入體內的有害物質也是通過氧化反應轉化為無毒的產品被排出體外。但是氧化反應能產生一些稱為自由基的分子,它們因失去電子而帶有正電荷,能與帶有負電荷的細胞膜、DNA、蛋白質等成分結合,對這些細胞組分造成損害,包括可能致癌的基因突變。自由基還能損傷向心臟供血的血管,誘發冠心病。而維生素C以及維生素A、E,Ω-3 脂肪酸(魚油的主要成分)等具有抗氧化劑作用的分子能夠給自由基提供所缺少的電子,消除它們對細胞組分的損害。這就是一般認為多吃水果蔬菜魚類等健康食品有助于延緩衰老,防止癌癥和心血管病的一個原因;也正因如此,抗氧化功能成為許多保健營養品最大的賣點。

          鮑林關于大劑量維生素C抗癌的理論,其邏輯倒也清楚:既然食物中的維生素C等抗氧化劑有助于防癌,那就是多多益善,應該大量補充。但他忽略了一個重要的事實:自由基既能對細胞造成損害,又是免疫系統消滅癌變細胞以及致病微生物的一大利器。維持健康的關鍵在于保持細胞內的氧化與抗氧化反應的平衡,長期服用超大劑量的抗氧化劑有可能破壞這種平衡,造成嚴重后果。在羅賓遜之后,又有各國研究人員進行了多次大規模的調查和研究,對象總數超過20萬人,發現服用巨量維生素(包括維C)的確增加了罹患多種癌癥的風險[15]

          維生素C與心臟病

          鮑林在他1986年出版的《怎樣活得更長更好》一書中宣稱,巨量維生素能“改進你的總體健康狀況……增加你生活的樂趣,幫助控制心臟病、癌癥及其它疾病,延緩衰老過程。”

          針對維生素C與心臟病的關系,1992年,91歲高齡的鮑林與德國醫生拉思(Matthias Rath)合作,在一份不受主流醫學界承認,不被美國國立醫學圖書館的MEDLINE 數據庫收錄的刊物《正分子醫學雜志》發表了一篇文章,題為《一項終將導致消除人類致命心血管病的統一理論》 [16]

          根據鮑林的這個理論,大約4千萬年前,人類的遠祖生活在溫暖的熱帶地區,以植物為主食,各種植物性食物中富含維生素C,不需要在體內自行合成,結果導致一個合成維C的關鍵酶——L-古洛糖酸內酯氧化酶的基因發生突變,永遠失去了像其它動物一樣自行合成維C的能力。后來隨著棲息地的遷移以及地球氣候變冷、冰川期到來,來自食物的維生素C營養成分大幅度減少,致使壞血病的發病率提高。而壞血病的主要特征是膠原蛋白、彈性蛋白等結締組織的主要成分的合成途徑受損,使血管壁的強度減弱,容易破裂,導致出血及死亡。壞血病因此成為冰川期對人類祖先的進化影響最大的自然選擇壓力。這種選擇壓力使得能促進動脈粥樣硬化的遺傳變異成為有利于生存的因素,因為動脈粥樣硬化是由于血液中的低密度脂蛋白(壞膽固醇)、脂蛋白a等成分在血管內壁沉積,形成斑塊,增加了血管壁的厚度及強度,從而減少了壞血病造成的出血和死亡。換句話說,動脈粥樣硬化是在人類祖先的進化過程中,通過自然選擇得到的在缺乏維生素C時有利于生存的性狀;動脈粥樣硬化造成的心血管病,則是這種選擇給今天的人類留下的健康隱患。

          盡管今天的人類已經不幸地繼承了那些能促進動脈粥樣硬化的遺傳基因,好在鮑林告訴我們,維生素C是對抗不利遺傳基因的救星,它幾乎對已知的任何一種心血管病的危險因素都有補救作用。維生素C能在代謝水平上抑制脂蛋白a的合成,促進膽固醇轉化為膽酸后經由膽管排出,從而減少血管斑塊的形成和心血管病的發生。但是要使維生素C的功效得以充分發揮,補充的量就必須達到人類的遠祖在失去合成維C能力之前,體內每天能制造的數量——10至20克。鮑林在文中沒有說明這個數據從何而來,大概是根據已知的今天一些哺乳動物合成維生素的能力推測的。

          文章的結尾總結道:“鑒于缺乏維生素C是人類心血管病的共同原因,補充維生素C就是這一疾病的普適療法。現有的流行病學及臨床研究結果相當可信地證明了這一點。這一理論在臨床上進一步證實后,心血管病將不再是我們這一代以及未來人類的死亡原因。”

          《統一理論》一文發表兩年后,1994年8月19日,鮑林因前列腺癌與世長辭。去世之前他接受過放射線治療。鮑林宣稱長年服用的維生素C將他的癌癥推遲了20年。這是個無法驗證的假設,自然不足為憑。

          鮑林在他這最后一篇重要文章中言之鑿鑿地提到的實驗證據是什么?

          1990年,鮑林和拉思曾在《美國科學院院報》發表一篇研究論文[17],報告豚鼠的飼料中如果缺少維生素C,就會造成動脈粥樣硬化,而且血管斑塊中含有脂蛋白a。如果給豚鼠按每千克體重每天補充40毫克維生素C(大約相當于2至3克的人類劑量),就可以防止脂蛋白a在血管壁沉積、造成粥樣硬化。鮑林據此推斷,維生素C對人類也有同樣效果。

          雖然豚鼠和人一樣不能自行合成維生素C,豚鼠畢竟不同于人類。不管鮑林的統一理論看上去多么漂亮,他所描繪的利用維生素C來永遠消除致命心血管病的美好愿景能否實現,歸根結底還要靠人體研究來檢驗。

          2016年,美國康涅狄格州立大學的兩位學者回顧總結了自1993年以來發表的關于維生素C與心臟健康的研究結果,包括7項觀察性的流行病學調查和6項隨機雙盲法臨床試驗。得到的發現是:維生素C的缺乏與心血管疾病死亡率的提高相關;但是對于補充維生素C能否降低心血管病的發病率和死亡率,證據依舊不足。許多研究沒有發現補充維生素C和心血管病的任何關聯,少數研究發現補充維生素C略有益處,但值得注意的是,也有一些研究發現維生素C補充劑增加了心血管疾病的風險,而且劑量不過是每天1克,只有已被確認的可耐受最高攝入量(2克)的一半。鑒于現有的研究結果不完全一致,兩位作者審慎地建議,對此還需要做進一步的研究[18]

          九泉之下的鮑林如若有知,還有耐心繼續等待嗎?

          鮑林的遺產

          鮑林的一生為人類留下的遺產是極為豐富而復雜的。天才的鮑林是將量子力學引入化學、將分子結構引入醫學、將蛋白質的氨基酸組分變化引入進化生物學的第一人。他是反對核武器和一切形式戰爭的堅強斗士。而晚年的鮑林則成為年銷售額320億美元的維生素保健品行業的精神教父。

          是什么因素使得曾經依靠嚴謹深入的研究和思辨,腳踏科學證據的基石步步攀登,征服了一座又一座科學高峰的鮑林,轉變為面對科學證據仍拒絕承認錯誤、一意孤行的鮑林?

          一種解釋是鮑林在他的科研生涯中,學術上曾經多次遭遇到強烈的反對意見,而最終被證明為錯誤的都是對方。久而久之,他終于形成了自己永遠正確的潛意識。

          鮑林的同行,同為諾貝爾化學獎得主的佩魯茨(Max Perutz)在高度贊譽鮑林的成就后,這樣評論道:“(維生素C)竟然成為鮑林最后25年中關心的頭等大事,使他作為化學家的崇高聲望受損,實在是個悲劇。這也許是由于他最大的弱點:虛榮心。換成愛因斯坦,假如有人對他提出不同意見,他會仔細思考,發現自己錯了,會很高興地改正,因為這使他避免了失誤。而鮑林則永遠不會承認自己的錯誤。” 佩魯茨隨后披露,他讀了鮑林關于蛋白質α-螺旋的論文后,發現其中一處計算有誤,就向鮑林指出,還以為鮑林會為此高興,豈料鮑林不但不表示感謝,反而憤怒地加以反擊,“因為他絕不能忍受別人發現了被他自己遺漏的東西。”[15]

          1954年諾貝爾化學獎頒獎儀式的當天晚上,幾百名瑞典大學生手持火炬游行,祝賀鮑林成為新的諾獎得主。鮑林應邀發表演說:“作為老一輩人,我想給你們一點忠告,應該怎樣對待長輩。”他清澈的聲音在廣場上回蕩,“當一個年長的大人物對你說話時,認真恭敬地聽,但別相信他。除了你自己的智慧,不要信任其它任何東西。一個老人,不管是白頭發或者沒頭發,哪怕他得過諾貝爾獎,也可能是錯的。你們必須永遠保持懷疑,永遠獨立思考。”學子們報以雷鳴般的掌聲和歡呼。

          當年,鮑林就是憑借這種懷疑一切、不迷信權威的批判精神,開辟了化學和分子生物學研究的新天地。

          今天,在我們不假思索地吞下幾克維生素C,或者一把其它保健營養品前,是不是也應該遵照鮑林的建議,先問幾個為什么,做一番獨立的研究和思考?


          主要參考資料

          1. US National Library of Medicine. Profiles in Science: Linus Pauling. https://profiles.nlm.nih.gov/spotlight/mm.

          2. OSU Libraries. Linus Pauling Online. http://scarc.library.oregonstate.edu/digitalresources/pauling/.


          其他參考文獻

          [1] Pauling L. Vitamin C and the Common Cold. San Francisco: WH Freeman, 1976.

          [2] Pauling L. Vitamin C, the Common Cold and the Flu. San Francisco: WH Freeman, 1976.

          [3] Pauling L. How to Live Longer and Feel Better. New York: WH Freeman, 1986.

          [4] Marshall CW. 2002. Vitamin C: Do High Doses Prevent Colds? https://www.quackwatch.org/01QuackeryRelatedTopics/DSH/colds.html)

          [5] Karlowski TR et al. Ascorbic acid and the common cold: A prophylactic and therapeutic trial. 1975. JAMA 231:1038-42.

          [6] Truswell AS. Ascorbic acid (letter). N Engl J Med. 1986. 315:709.

          [7] Cameron E & Pauling L. Supplemental ascorbate in the supportive treatment of cancer: Prolongation of survival times in terminal human cancer. Proc Natl Acad Sci USA. 1976. 73: 3685-9.

          [8] Cameron E & Pauling L. Supplemental ascorbate in the supportive treatment of cancer: reevaluation of prolongation of survival times in terminal human cancer. Proc Natl Acad Sci USA 1978. 75: 4538-42.

          [9] Pauling L. On cancer and vitamin C. Prevention 1979. 31: 54.

          [10] DeWys WD. How to evaluate a new treatment for cancer. Your Patient and Cancer 1982. 2: 31-6.

          [11] Creagan ET et al. Failure of high-dose vitamin C (ascorbic acid) therapy to benefit patients with advanced cancer. A controlled trial. N Engl J Med. 1979. 301: 687-90.

          [12] Moertel CG et al. High-dose vitamin C versus placebo in the treatment of patients with advanced cancer who have had no prior chemotherapy. A randomized double-blind comparison. N Engl J Med. 1985. 312: 137-41.

          [13] Tschetter L et al. A community-based study of vitamin C (ascorbic acid) in patients with advanced cancer. Proceedings of the American Society of Clinical Oncology. 1983. 2: 92.

          [14] Barrett S. High Doses of Vitamin C Are Not Effective as a Cancer Treatment. 2011. https://www.quackwatch.org/01QuackeryRelatedTopics/Cancer/c.html

          [15] Offit PA. Pandora’s Lab. Washington DC: National Geographic, 2017.

          [16] Rath M & Pauling L. A Unified Theory of Human Cardiovascular Disease Leading the Way to the Abolition of This Disease as a Cause for Human Mortality. Journal of Orthomolecular Medicine. 1992. 7: 5-12.

          [17] Rath M & Pauling L. Immunological evidence for the accumulation of lipoprotein(a) in the atherosclerotic lesion of the hypoascorbemic guinea pig. Proc Natl Acad Sci USA. 1990. 87: 9388-90.

          [18] Moser MA & Chun OK. Vitamin C and Heart Health: A Review Based on Findings from Epidemiologic Studies. Int J Mol Sci. 2016 17(8). pii: E1328. doi: 10.3390/ijms17081328.

          特 別 提 示

          1. 進入『返樸』微信公眾號底部菜單“精品專欄“,可查閱不同主題系列科普文章。

          2. 『返樸』開通了按月檢索文章功能。關注公眾號,回復四位數組成的年份+月份,如“1903”,可獲取2019年3月的文章索引,以此類推。

          版權說明:歡迎個人轉發,任何形式的媒體或機構未經授權,不得轉載和摘編。轉載授權請在「返樸」微信公眾號內聯系后臺。

          《返樸》,科學家領航的好科普。國際著名物理學家文小剛與生物學家顏寧共同出任總編輯,與數十位不同領域一流學者組成的編委會一起,與你共同求索。關注《返樸》(微信號:fanpu2019)參與更多討論。二次轉載或合作請聯系返樸公眾號后臺。

          開發者,在后端僅提供原始數據集的情況下,如何讓所有搜索邏輯都在前端完成?不僅如此,還要能夠實現預測用戶輸入、忽略錯別字輸入、快速自動補齊等智能功能?本文的作者就深入 JavaScript 技術特性,談一談 React、性能優化以及多線程那些事兒。



          作者 | Leo Fabrikant

          譯者 | 彎月,責編 | 郭芮

          出品 | CSDN(ID:CSDNnews)

          以下為譯文:



          第一篇 問題闡述


          我有一個看似很簡單的任務:“有一個從后端檢索的數據集,其中包含13,000個數據項,每一項都是冗長羅嗦的名稱(科學組織)。使用這些數據創建一個帶自動補齊功能的搜索欄。”

          你也不覺得很難,對不對?

          難點1:

          不能使用后端。后端只能提供原始的數據集,所有搜索邏輯都必須在前端完成。

          難點2:

          開發人員(我):“這些組織名稱這么長,需要花點心思。如果我們只是運行簡單的字符串匹配,而且用戶可能會輸錯或出現拼寫錯誤,那么就很難搜索到任何結果。”

          客戶:“你說的對,我們必須加入一些智能的功能,預測用戶的輸入,忽略輸入的錯別字。”

          注意:一般情況下,我不建議你在未經項目經理同意下,提示客戶沒有提到的復雜功能!這種情況稱為特征蔓延(feature creep)。在上述例子中,只是恰巧我一個人負責這個合同,我有足夠的精力,所以我認為這是一個有趣的挑戰。

          難點3:

          這是最大的難點。我選擇的智能(也稱為“模糊”)搜索引擎非常慢……

          隨著搜索詞的長度加長,這個搜索算法庫的搜索時間會迅速增加。此外,看看下面這個龐大的列表,里面的數據項極其冗長,用戶需要輸入一個很長的搜索詞才能出現自動補齊提示。別無他法,搜索引擎跟不上用戶的打字速度,這個UI可能會廢掉。




          我不知道是不是因為我選擇的這個搜索算法庫太過糟糕,我也不知道是不是因為所有“模糊”搜索算法都是這樣的情形。但幸運的是,我沒有費心去尋找其他選擇。

          盡管上述難點大多數是我自己強加上去的,但我依然決定堅持到底,努力優化這種實現。雖然我知道這可能不是最佳策略,但是這個項目的情況允許我這么做,結果將說明一切,最重要的是,對我來說這是一次絕佳的學習體驗和成長的機會。



          第二篇 問題剖析


          在第一個實現中,我使用了UI的react-autocomplete和react-virtualized庫。

          render () {
           return (
           <Autocomplete
           value={this.state.searchTerm}
           items={this.getSearchResults()}
           renderMenu={this.reactVirtualizedList}
           renderItem={this.renderItem}
           getItemValue={ item => item.name }
           onChange={(e, value) => this.setState({searchTerm: value})}
           />
           )
           }
          


          Autocomplete組件需要傳遞以下幾項:value屬性,需要傳入輸入框中的searchTeam;items屬性,傳入搜索結果;以及renderMenu函數,該函數將搜索結果列表傳遞給react-vertualized。

          react-virtualized能夠很好地處理大型列表(它只會渲染列表顯示在屏幕上的一小部分,只有滾動列表時才會更新)。考慮到我們需要渲染的組件并不多,我認為應該不會有太嚴重的性能問題。

          更新操作的聲明周期也很簡單:

          • 用戶輸入'a'
          • Autocomplete的onChange處理函數觸發一次渲染,此時this.state.searchTeam = 'a'
          • 該渲染會調用getSearchResults方法,在這個方法中,搜索引擎使用'a'作為搜索關鍵字計算搜索結果,然后將結果傳遞給react-virtualized負責渲染。


          getSearchResults = () => {
           const {searchTerm} = this.state;
           return searchTerm ? this.searchEngine.search(searchTerm) : []
           // searchEngine.search is the expensive search algorithm
          };
          


          我們來看看結果如何:




          哎呀……很糟。在按住刪除鍵時的的確確能感覺到UI的停頓,因為鍵盤觸發delete事件太快了。

          不過至少模糊搜索好用了:'anerican'正確地解釋成了'American'。但隨著搜索關鍵字的加長,兩個元素(輸入框和搜索結果)的渲染過程完全跟不上用戶輸入的速度,延遲非常大。

          盡管我們的搜索算法的確很慢,但如此大的延遲并不是由于單次搜索時間太長導致的。這里還有另外一個現象需要理解:我們管它叫UI阻塞。理解這個現象需要深入了解Chrome的DevTools性能評測工具。

          性能評測

          可能你不熟悉這個工具,但是你要知道,熟練使用性能評測工具是深入理解JavaScript的最好方式。這不僅因為它能提供有用的信息幫你解決各種問題,而且按照時間顯示出JavaScript的執行過程能夠幫助你更好地理解好的UI、React、JavaScript事件循環、同步異步執行等概念。

          在下面每一節,我都會給出性能分析過程,以及從這些過程中推斷出的有趣的結論。這些數據可能會讓你眼花繚亂,但我會盡力給出合理的解釋!

          首先評測一下在Autocomplete中按下兩個鍵時的情況:



          X軸:時間,Y軸:按照類型排列的事件(用戶輸入、主線程函數調用)


          理解基本的序列非常重要:

          首先是用戶的鍵盤輸入(Key Characer)。這些輸入在JavaScript的主線程上觸發了Event(keypress)事件,該事件又觸發了我們的onChange處理函數,該函數會調用setState(圖上看不見,因為它太小了,但它的位置在整個棧的最開頭附近)。這一系列動作標志著重新計算的開始,計算setState對組件會產生何種影響。這一過程稱為更新,或者叫做重新渲染,它會調用幾個React生命周期方法,其中就包括render。這一切都發生在一個執行棧(有時稱為“調用棧”或簡稱為“棧”),在圖中由每個Event (keypress)下方豎直排列的框表示。每個框都是執行棧中的一次函數調用。

          這里不要被render這個詞誤導了。React的渲染并不僅僅是在屏幕上繪制。渲染只是React用來計算被更新的元素應當如何顯示的過程。如果仔細查看第二個Event (keypress),就會發現在Event (keypress)框的外面有個小得幾乎看不見的綠條。放大一些就能看到這是對瀏覽器繪制的調用:




          這才是UI更新被真正繪制到屏幕上,并在顯示器上顯示新幀的過程。而且,第一個Event (keypress)之后沒有繪制,只有第二個后面才有。

          這說明,瀏覽器繪制(外觀上的更新)并不一定會在Event (keypress)事件發生并且React完成更新之后發生。

          原因是JavaScript的事件循環和JavaScript對于任務隊列的優先級處理。在React結束計算并將更新寫入DOM之后(稱為提交階段,發生在每個執行棧末尾的地方),你可能會以為瀏覽器應該開始繪制,將DOM更新顯示在屏幕上。但是在繪制之前,瀏覽器會檢查JavaScript事件隊列中是否還有其他任務,有的任務會比繪制更優先執行。

          當JavaScript線程忙于渲染第一個keypress時,產生第二個用戶輸入(如鍵盤按下事件)就會出現這種情況(你可以看到第二個Key Character輸入發生在第一個keypress執行棧依然在運行時)。這就是前面提到的UI阻塞。第二個Event (keypress)阻塞了UI更新第一個keypress。

          不幸的是,這會導致巨大的延遲。因為渲染本身非常慢(部分原因是因為渲染中包含了昂貴的搜索算法),如果用戶輸入非常快,那么很大可能會在前一個執行棧結束之前輸入新的字符。這會產生新的Event (keypress),并且它的優先級比瀏覽器繪制要高。所以繪制會不斷被用戶的輸入拖延。

          不僅如此,甚至在用戶停止輸入后,隊列中依然滯留了許多keypress時間,React需要依次對每個keypress進行計算。所以,即使在輸入結束后,也不得不等待這些針對早已不需要的searchTeams的搜索!




          注意最后一個Key Character發生后,還有4個Event (keypress)滯留,瀏覽器需要處理完所有事件才能重繪。

          改進方法

          為了解決這個問題,重要的是要理解好的UI的要素是什么。實際上,對于每次鍵盤輸入,用戶期待的視覺反饋包括兩個獨立的要素:

          • 用戶輸入的鍵顯示在輸入框中;
          • 搜索結果根據新的searchTeam進行更新。


          理解用戶的期望才能找到解決方案。盡管Google搜索快得像閃電一樣,但用戶無法立即收到搜索結果的事情也屢見不鮮。一些UI甚至會在請求搜索結果時顯示加載進度條。

          重要的是要理解,對于反應迅速的UI而言,第一種反饋(按下的鍵顯示在輸入框中)扮演了非常重要的角色。如果UI無法做到這一點,就會有嚴重的問題。

          查看性能評測是解決問題的第一個提示。仔細觀察這些長長的執行棧和render中包含的昂貴的search方法,我們會發現,更新輸入框和搜索結果的一切操作都發生在同一個執行棧內。所以,兩者的UI更新都會被搜索算法阻塞。

          但是,輸入框的更新不需要等待結果!它只需要知道用戶按下了哪個鍵,而不需要知道搜索結果是什么。如果我們有辦法控制事件執行的順序,輸入框就有機會先更新UI,再去渲染搜索結果,這樣就能減少一些延遲。因此,我們的第一個優化措施就是將輸入框的渲染從搜索結果的渲染中分離出來。

          注意:熟悉Dan Abramov在React JSConf 2018上的演講的人應該能回憶起這個場景。在他的幻燈片中,他設計了一個昂貴的更新操作,隨著輸入值的增加,屏幕上需要渲染的組件也越來越多。這里我們遇到的困難非常相似,只不過是隨著搜索關鍵字長度的增加,單個搜索函數的復雜度會增加而已。在Dan的演講中,他演示了時間切片(Time Slicing),這個React團隊在開發中的功能也許可以解決這個問題!我們的嘗試會以相似的方案解決問題:找到一個方法來改變渲染的順序,防止昂貴的計算再次阻塞主線程的UI更新。



          第三篇 異步渲染(componentDidUpdate)


          注意:本篇討論的優化最后以失敗告終了,但我認為值得講一講,因為它能幫助我們更好地理解React的componentDidUpdate生命周期。如果你非常熟悉React,或者只想看看怎樣改善性能問題,那么可以直接跳到下一篇。

          拆分組件

          由于我們想把昂貴的搜索結果更新從輸入框更新中拆分出來,所以我們應該自己設計一個組件,并放棄使用react-autocomplete庫提供的一站式解決方案Autocomplete:

          //autocomplete.js
          render () {
           return (
           <div>
           <input
           onChange={ e => this.setState({searchTerm: e.target.value})}
           value={this.state.searchTerm}/>
           <SearchResults
           searchEngine={this.props.searchEngine}
           searchTerm={this.state.searchTerm}/>
           </div> 
           )
          }
          


          然后在SearchResults中,我們需要異步觸發searchEngine.search(searchTerm),而不應該在更新searchTerm的同一個渲染中進行。

          我最初的想法是利用SearchResults的componentDidUpdate,讓searchEngine異步工作,因為聽上去這個方法似乎是在更新之后異步執行的。

          //searchResults.js
          componentDidUpdate(prevProps) {
           const {searchTerm, searchEngine} = this.props;
           if(searchTerm && searchTerm !== prevProps.searchTerm) {
           this.setState({
           searchResults: searchEngine.search(searchTerm)
           })
           }
          }
          render () {
           return <ReactVirtualizedList searchResults={this.state.searchResults}/>
          }
          


          我們將昂貴的searchEngine移動到了componentDidUpdate中,這樣就不用在render方法中調用,而是等到更新之后再執行。我希望在輸入框更新之后的另一個執行棧中執行render,并兩者之間執行一次繪制。我想象的新的更新生命周期如下:

          • 輸入框使用新的searchTerm渲染;
          • React把帶有新的searchTerm的componentDidUpdate searchEngine任務放入隊列;
          • 瀏覽器繪制輸入框的更新,然后處理隊列中的searchEngine任務。理論上,瀏覽器不會把這個任務放在繪制任務之前,因為它不涉及用戶交互事件;
          • componentDidUpdate在輸入框繪制之后執行,計算搜索結果并生成新的更新。


          很不幸,認為componentDidUpdate會在瀏覽器更新之后運行是一個常見的誤解。我們來看看這個方法的性能評測:




          看到問題了嗎?componentDidUpdate跟最初的keypress事件是在同一個執行棧上執行的

          componentDidUpdate并不會在繪制結束后執行,因此執行棧跟上一篇一樣昂貴,我們只不過是將昂貴的search方法移動到了不同位置而已。盡管這個解決方案并不能改善性能,但我們可以借此機會理解React的生命周期componentDidUpdate的具體行為。

          雖然componentDidUpdate不會在另一個執行棧上運行,但它確實是在React更新完組件狀態并將更新后的DOM值提交之后才執行的。盡管這些更新后的DOM值還沒有被瀏覽器繪制,它們依然反映了更新后的UI應有的樣子。所以,任何componentDidupdate內執行的DOM查詢都能訪問到更新后的值。所以,組件確實更新了,只是瀏覽器中看不見而已。

          所以,如果想要做DOM計算,一般都應該在componentDidUpdate中進行。在這里很方便根據布局改變進行更新,比如根據新的布局方式計算元素的位置或大小,然后更新狀態等。

          如果componentDidUpdate每次觸發改變布局的更新時都要等待實際的瀏覽器繪制,那么用戶體驗會非常糟糕,因為用戶可能會在布局改變時看到兩次屏幕閃爍。

          注(React Hooks):這個差異也有助于理解新的useEffect和useLayoutEffect鉤子。useEffect就是我們在這里嘗試實現的效果。它會讓代碼在另一個執行棧中運行,從而在執行之前瀏覽器可以進行繪制。而useLayoutEffect更像是componentDidUpdate,允許你在DOM更新之后、瀏覽器繪制之前執行代碼。



          第四篇 異步渲染(setTimeout)


          上一篇我們拆分了組件:

          //autocomplete.js
          render () {
           return (
           <div>
           <input
           onChange={ e => this.setState({searchTerm: e.target.value})}
           value={this.state.searchTerm}/>
           <SearchResults
           searchEngine={this.props.searchEngine}
           searchTerm={this.state.searchTerm}/>
           </div> 
           )
          }
          


          但我們沒能讓昂貴的searchEngine在另一個執行棧上運行。那么,還有什么辦法能實現這一點呢?

          有兩個常見的方法可以設置異步調用:Promise和setTimeout。

          Promise

          //searchResults.js
          componentDidUpdate(prevProps) {
           const {searchTerm, searchEngine} = this.props;
           if(searchTerm && searchTerm !== prevProps.searchTerm) {
           /* stick the update with the expensive search method into
           a promise callback: */
           Promise.resolve().then(() => {
           this.setState({
           searchResults: searchEngine.search(searchTerm)
           })
           })
           }
          }
          render () {
           return <ReactVirtualizedList searchResults={this.state.searchResults}/>
          }
          


          我們來看看性能評測:



          (anonymous)是Promise.then()回調函數


          又失敗了!

          理論上Promsie的回調函數是異步的,因為它們不會同步執行,但實際上還是在同一個執行棧中運行的。

          仔細看看性能評測就會發現,回調函數被放在了Run Microtasks下,因為Promise的回調函數被當作了微任務。瀏覽器通常會在完成正常的棧之后檢查并運行微任務。

          更多信息:Jake Archibald有一篇非常好的演講(https://medium.com/r/?url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DcCOL7MC4Pl0),解釋了JavaScript事件循環在微任務方面的處理,還深入討論了許多我涉及到的話題。

          盡管了解這一點很好,但并沒有解決問題。我們需要新的執行棧,這樣瀏覽器才有機會在新的執行棧開始之前進行繪制。

          setTimeout

          //searchResults.js
          componentDidUpdate(prevProps) {
           const {searchTerm, searchEngine} = this.props;
           if(searchTerm && searchTerm !== prevProps.searchTerm) {
           /* stick the update with the expensive search method into
           a setTimeout callback: */
           const setTimeoutCallback = () => {
           this.setState({
           searchResults: searchEngine.search(searchTerm)
           })
           }
           setTimeout(setTimeoutCallback)
           }
          }
          render () {
           return <ReactVirtualizedList searchResults={this.state.searchResults}/>
          }
          


          性能評測:



          繪制很難看到,它太小了,但藍線的位置的確發生了繪制


          哈哈!成功了!注意到這里有兩個執行棧:Event (keypress)和Timer Fired (searchResults.js:49)。兩個棧之間發生了一次繪制(藍線的位置)。這正是我們想要的!來看看漂亮的UI!



          按住刪除鍵時依然有明顯的延遲


          有很大的改進,但依然很令人失望……這個頁面的確變好了,但依然能感覺到UI的延遲。我們來仔細看看性能測試。




          我們需要一些技巧才能分析這個性能測試報告并找出延遲的原因。使用性能報告有幾個小技巧:

          性能評測工具著重顯示了兩個特別有用的Key Input Interactions,每個都有不同的性能度量:

          • Key Down:從鍵盤按下到Event (keypress)處理函數被調用的時間間隔;
          • Key Character:從鍵盤按下到瀏覽器繪制更新的時間間隔。


          理想狀態下,Key Down交互應該非常短,因為如果JavaScript主線程沒有被阻塞的話,事件應該在鍵盤按下之后立即出發。所以,看到長長的Key Down就意味著發生了UI阻塞問題。

          在本例中,長長的Key Down的原因是它們觸發時,主線程還在被昂貴的setTimeoutCallback阻塞,比如最后的Key Down。很不幸,Key Down發生時,運行昂貴的search的setTimeoutCallback剛剛開始,也就是說,Key Down只有等待search的計算結束才能觸發事件。這個評測中的search方法大約花了330毫秒,也就是1/3秒。從優秀的UI角度而言,1/3秒的主線程阻塞實在太長了。

          特別引起我注意的是最后一個Key Character。盡管它關聯了Key Down的結束并且觸發了Event (keypress),瀏覽器并沒有繪制新的searchTerm,而是執行了另一個setTimeoutCallback。這就是Key Character交互花了兩倍時間的原因。

          這一點著實讓我大跌眼鏡。將search移動到setTimeoutCallback的目的,就是讓瀏覽器能夠在調用setTimeoutCallback之前進行繪制。但是在最后的Event (keypress)之前依然沒有繪制(藍線的位置)。

          結論是,我們不能依賴于瀏覽器的隊列機制。顯然瀏覽器并不一定將繪制排在超時回調之前。如果超時回調需要占用主線程330毫秒,那么也會阻礙主線程,導致延遲。



          第五篇 多線程


          在上一篇中,我們拆分了組件,并成功地使用setTimeout將昂貴的search移動到了另一個執行棧中,因此瀏覽器無需等待 search完成,就可以繪制輸入框的更新:

          //autocomplete.js
          render () {
           return (
           <div>
           <input
           onChange={ e => this.setState({searchTerm: e.target.value})}
           value={this.state.searchTerm}/>
           <SearchResults
           searchEngine={this.props.searchEngine}
           searchTerm={this.state.searchTerm}/>
           </div> 
           )
          }
          //searchResults.js
          componentDidUpdate(prevProps) {
           const {searchTerm, searchEngine} = this.props;
           if(searchTerm && searchTerm !== prevProps.searchTerm) {
           const setTimeoutCallback = () => {
           this.setState({
           searchResults: searchEngine.search(searchTerm)
           })
           }
           setTimeout(setTimeoutCallback)
           }
          }
          render () {
           return <ReactVirtualizedList searchResults={this.state.searchResults}/>
          }
          


          不幸的是,這依然沒有解決每個searchTerm導致search阻塞主線程330毫秒并導致UI延遲的問題。

          JavaScript的單線程實在太糟糕了……突然我想到了一個方法。

          最近我在閱讀漸進式Web應用,其中有人使用Service Worker來實現一些過程,比如在另一個線程中進行緩存。于是我開始學習Service Worker。這是一個全新的API,我需要花點時間來學習。

          但在學習之前我想先通過實驗來驗證一下增加額外的線程是否真的能夠提高性能。

          用服務器端來模擬第二個線程

          我以前就做過搜索和自動補齊提示的功能,但這次特別困難的原因是需要完全在前端實現。以前我做過用API來獲取搜索結果。其中一種思路是,API和運行API的服務器實際上相當于前端應用利用的另一個線程。

          于是,我想到可以做一個簡單的node服務器讓searchTerm訪問,從而實現在另一個線程中運行昂貴的搜索。這個功能非常容易實現,因為這個項目中已經設置過開發用的服務器了。所以我只需添加一個新的路徑:

          app.route('/prep-staging/testSearch')
           .post(bodyParser.json(), (req, res) => {
           const {data, searchTerm} = req.body
           const engine = new SearchEngine(data)
           const searchResults = engine.search(searchTerm)
           res.send({searchResult})
           })
          


          然后將SearchResults中的setTimeout改成fetch:

          //searchResults.js
          componentDidUpdate(prevProps) {
           const {searchTerm, searchEngine, data} = this.props;
           if(searchTerm && searchTerm !== prevProps.searchTerm) {
           /* ping the search route with the searchTerm and update state
           with the results when they return: */
           fetch(`testSearch`, {
           method: 'POST',
           body: JSON.stringify({data, searchTerm}),
           headers: {
           'content-type': 'application/json'
           }
           })
           .then(r => r.json())
           .then(resp => this.setState({searchResults: resp.searchResults}))
           }
          }
          render () {
           return <ReactVirtualizedList searchResults={this.state.searchResults}/>
          }
          


          現在是見證奇跡的時刻!




          注意看刪除!

          太棒了!輸入框的更新幾乎非常完美。而另一方面,搜索結果的更新依然非常緩慢,但沒關系!別忘了我們的首要任務就是讓用戶在輸入時盡快獲得反饋。我們來看看性能測試報告:




          注意主線程中間漂亮的空白,它不再是之前層層疊疊的樣子了。性能優化中經常會遇到這種情況。主線程中的空白越多越好!

          從頂端可以看到testSearch花費的時間。最長的一個實際上花了800毫秒,讓我很吃驚,但仔細想想就會發現,并不是search花了這么長時間,而是我們的Node服務器也是單線程的。它在第一個搜索完成之前無法開始另一個搜索。由于輸入比搜索快得多,所以搜索會進入隊列然后被延遲。搜索函數實際花費的時間是前一個搜索完成之后的部分,大約315毫秒。

          總的來說,將昂貴的任務放到服務器線程中,就可以將堆疊的棧移動到服務器上。所以,盡管依然有改進的空間,但主線程看起來非常好,UI的響應速度也更快了!

          我們已經證明這個思路是正確的,現在來實現吧!

          做了一點研究后我發現,Server Worker并不是正確的選擇,因為它不兼容Internet Explorer。幸運的是,它還有個近親,叫做Web Worker,能兼容所有主流服務器,API更簡單,而且能完成我們需要的功能!



          第六篇 Web Worker


          Web worker能夠在JavaScript的主線程之外的另一個線程上運行代碼,每個Web worker都由一個腳本文件啟動。啟動方式非常簡單:

          //searchResults.js
          export default class SearchResults extends React.Component {
           constructor (props) {
           super();
           this.state = {
           searchResults: [],
           }
           //initiate the webworker:
           this.webWorker = new Worker('...path to webWorker.js') 
           //pass it the 13,000 item search data to initialize the searchEngine with:
           this.webWorker.postMessage({data: props.data})
           //assign the handler that will accept the searchResults when it sends them back:
           this.webWorker.onmessage = this.handleResults
           }
           componentDidUpdate(prevProps) {
           const {searchTerm} = this.props;
           if(searchTerm && searchTerm !== prevProps.searchTerm) {
           //change our async search request to a .postMessage, the messaging API of webWorkers:
           this.webWorker.postMessage({searchTerm})
           }
           }
           handleResults = (e) => {
           const {searchResults} = e.data
           this.setState({
           searchResults
           })
           }
           render () {
           return <ReactVirtualizedList searchResults={this.state.searchResults}/>
           }
          }
          


          下面是webWorker.js腳本,在SearchResults的構造函數中進行初始化:

          //webWorker.js
          self.importScripts('...the search engine script, provides the SearchEngine constructor');
          let searchEngine; 
          let cache = {} 
          //thought I would add a simple cache... Wait till you see those deletes now :)
          function initiateSearchEngine (data) {
           //initiate the search engine with the 13,000 item data set
           searchEngine = new SearchEngine(data); 
           //reset the cache on initiate just in case
           cache = {}; 
          }
          function search (searchTerm) {
           const cachedResult = cache[searchTerm]
           if(cachedResult) {
           self.postMessage(cachedResult)
           return
           }
           const message = {
           searchResults: searchEngine.search(searchTerm)
           };
           cache[searchTerm] = message;
           //self.postMessage is the api for sending messages to main thread
           self.postMessage(message)
          }
          /*self.onmessage is where we define the handler for messages recieved
          from the main thread*/
          self.onmessage = function(e) {
           const {data, searchTerm} = e.data;
           /*We can determine how to respond to the .postMessage from 
           SearchResults.js based on which data properties it has:*/
           if(data) {
           initiateSearchEngine(data)
           } else if(searchTerm) {
           search(searchTerm)
           }
          }
          


          可以看到,我還加了些額外的代碼。這里我加了緩存,這樣之前搜索過的searchTerms就可以立即返回結果了。如此一來,最耗性能的用戶交互(常按刪除鍵)的效率就提高了。

          我們來看看運行情況:




          太棒了……非常快!這看起來很不錯啊,實話說,做到這個樣子就可以直接發布了!

          但是,現在就發布多沒勁啊……

          從用戶體驗的角度來說,這個UI已經非常好了。如果仔細觀察,其實依然能看到搜索結果的延遲,但幾乎察覺不到……不過幸運的是,從性能測試報告中可以看到低效率的地方:




          請無視灰色的條,我也不知道它們是怎么來的。

          報告中最左側的線程是我們關注的線程。Main線程已經折疊了,因為里面只有大量的空白,意味著主線程的性能非常好,不會成為任何主要的性能瓶頸。

          可以看到,Worker線程里堆滿了search調用。從最后一個Key Character輸入(藍線位置)之后就會看到其后果。Worker線程中的最后一個search實際上推遲了3個search才返回。測量一下會發現,延遲大約有850毫秒。而且大部分都是不必要的,因為那三個search都沒用,我們不再需要它們返回的結果了。

          你也許在想:“這已經很好了!再優化下去性價比不高啊!”

          我不這樣認為。首先,不要低估嘗試新事物和探索帶來的價值。如果你從來沒做過探索,就很可能無法評價是否值得,因為你不知道你能有哪些收獲,以及你將投入多少時間和努力。所以,我認為這種探索帶來的經驗和知識是無價的。隨著知識的積累,你能更好地評價投入的時間是否值得,以及是否應該考慮這些問題。你可以做出更好的決定!

          其次,別忘了這并不是過早優化。這些優化都是根據性能評價做出的,我們可以測量出效果。不管怎樣評價,如果能改善850毫秒的延遲,那都是非常重大的改進。

          最后(但不是唯一),別忘了移動端!雖然我不會在本文中介紹,但我在研究這個問題時,我也跟蹤了移動端的性能,現在的條件下依然有能察覺得到的性能延遲。

          不管怎么說,我們來解決這個問題!



          第七篇 確保searchTerm


          前面的性能評測揭示的最明顯的問題就是,即使對于無用的searchTerm也會運行昂貴的搜索。所以目前的解決方案之一就是在執行昂貴的搜索之前確保searchTerm是最新的。只要在webWorker腳本中加入confirmSearchTerm就可以非常容易地實現:

          //webWorker.js
          self.importScripts('...the search engine script, provides the SearchEngine constructor');
          let searchEngine; 
          let cache = {}
          function initiateSearchEngine (data) {
           searchEngine = new SearchEngine(data);
           cache = {};
          }
          function search (searchTerm) {
           const cachedResult = cache[searchTerm]
           if(cachedResult) {
           self.postMessage(cachedResult)
           return
           }
           const message = {
           searchResults: searchEngine.search(searchTerm)
           };
           cache[searchTerm] = message;
           self.postMessage(message)
          }
          function confirmSearchTerm (searchTerm) {
           self.postMessage({confirmSearchTerm: searchTerm})
          }
          self.onmessage = function(e) {
           const {data, searchTerm, confirmed} = e.data;
           if(data) {
           initiateSearchEngine(data)
           } else if(searchTerm) {
           /*check if the searchTerm is confirmed, if not, send a confirmSearchTerm message 
           to compare the searchTerm with the latest value on the main thread */
           confirmed ? search(searchTerm) : confirmSearchTerm(searchTerm)
           }
          }
          


          這里還給SearchResults handleResults加了個額外的條件,監聽confirmSearchTerm的請求:

          //searchResults.js
          export default class SearchResults extends React.Component {
           constructor (props) {
           super();
           this.state = {
           searchResults: [],
           }
           this.webWorker = new Worker('...path to webWorker.js') 
           this.webWorker.postMessage({data: props.data})
           this.webWorker.onmessage = this.handleResults
           }
           componentDidUpdate(prevProps) {
           const {searchTerm} = this.props;
           if(searchTerm && searchTerm !== prevProps.searchTerm) {
           this.webWorker.postMessage({searchTerm})
           }
           }
           handleResults = (e) => {
           const {searchResults, confirmSearchTerm} = e.data;
           /* check if confirmSearchTerm property was sent, if so compare it to the 
           latest searchTerm and send back a confirmed searchTerm message */
           if (confirmSearchTerm && confirmSearchTerm === this.props.searchTerm) {
           this.webWorker.postMessage({
           searchTerm: this.props.searchTerm,
           confirmed: true
           })
           } else if (searchResults) {
           this.setState({
           searchResults
           })
           }
           }
           render () {
           return <ReactVirtualizedList searchResults={this.state.searchResults}/>
           }
          }
          


          我們來看看性能評測,看看有沒有改進:




          很難看出結果,因為它們運行得太快了,但在每次Worker的執行棧之前都會執行confirmSearchTerm(見藍線)。

          說明的確管用了:Worker在每次運行昂貴的search方法之前都會確認搜索是否必要。而且可以看到,頂部的橙色部分有4個Key Character輸入,但只運行了三個搜索。這里我們成功地去掉了一個不必要的搜索,節約了最多330毫秒。但之前我們看到,多個額外的搜索會進入隊列然后再不必要地運行,而現在我們完全避免了這個問題。所以,節約的時間非常顯著,特別是在移動端上。

          但仔細觀察就會發現我們依然在浪費時間:




          最后一個搜索使用了最新的searchTerm,但依然要至少等待當前的搜索完成后才能開始。浪費了84毫秒(藍色高亮部分)!據我所知,執行棧一旦開始就無法取消。那么我們是不是無計可施了呢?



          第八篇 Web Worker陣列


          如果多加一個線程的效果很好,那么加4個會怎樣?

          實話實說,現在這些只是出于興趣……但說真的,最后這次優化確實在移動端上帶來了人眼能察覺到的改善……

          無論怎樣,現在我打算用Web Worker陣列!




          為了出這份報告,我用人類最快的速度輸入的!

          圖中可以看到,頂端每個橙色的Key Character都有一個ww worker線程,能立即開始搜索(橙色條)。不再需要等待前一個搜索結束。而且每個ww在結束后就能用于下一次搜索。

          這是因為我們設置了workerArray.js這個web worker作為分發器。圖中看不到,因為它執行得太快了,但對于每個Key Character,workerArray都會執行一個微笑的執行棧,用來處理主線程傳來的搜索請求消息,然后分發給第一個可用的ww worker。

          我們成功地解決了“搜索堆”的問題。可以認為用增加車道的方式解決了交通擁堵。

          為什么用4個搜索worker呢?因為我在測試時的輸入速度從來沒能到過需要第五個worker的速度(增加worker帶來的改進非常微小)。

          結果發現,從Key Character輸入到search執行之間沒有任何延遲。除非找到另一個更有效的搜索算法,否則我們已經成功地移除了所有性能瓶頸。

          別忘了,我并沒有說這是最佳的解決方案。是否每臺手機都能處理4個web worker?性能改善是否值得付出這些額外的代碼復雜度?是否還有其他安全方面的考量,導致代碼更加復雜?

          這些問題都非常重要,正是這些問題會最終引出這樣的解決方案。

          但至少現在,這個Web worker陣列非常優秀!我們來看看實際效果:




          感謝你耐心地閱讀完所有的篇節!

          如果說這一系列優化有什么感想的話,那就是:

          • 不要害怕嘗試新事物,不要害怕不尋常的方案。
          • 方案是否好用并不重要,它們帶來的經驗和知識才是最有價值的!


          如果你有興趣,可以看看下面Web worker陣列的代碼。



          課外作業


          下面的代碼中有個小問題。需要一個非常微小的修改才能使它更強壯,最多兩行代碼。你能找到問題所在并修復嗎?

          //searchResults.js
          export default class SearchResults extends React.Component {
           constructor (props) {
           super();
           this.state = {
           searchResults: [],
           }
           //initiate the worker array:
           this.workerArray = new WorkerArrayController({
           data: props.data,
           handleResults: this.handleResults,
           arraySize: 4
           });
           }
           componentDidUpdate(prevProps) {
           const {searchTerm} = this.props;
           if(searchTerm && searchTerm !== prevProps.searchTerm) {
           this.workerArray.search({searchTerm})
           }
           }
           handleResults = (e) => {
           const {searchResults} = e.data
           this.setState({
           searchResults
           })
           }
           componentWillUnmount () {
           this.workerArray.terminate();
           }
           render () {
           return <ReactVirtualizedList searchResults={this.state.searchResults}/>
           }
          }
          


          SearchResults組件初始化WorkerArrayController。

          //workerArrayController.js
          export default class WorkerArrayController {
           constructor ({data, handleResults, arraySize}) {
           this.workerArray = new Worker('... path to workerArray.js');
           let i = 1;
           this.webWorkers = {};
           while (i <= arraySize) {
           const workerName = `ww${i}`;
           this.webWorkers[workerName] = new Worker(`...path to ww1.js`);
           /* Creates a MessageChannel for each worker and passes that channel's 
           ports to both workerArray dispatcher and the worker so 
           they can communicate with each other */
           const channel = new MessageChannel();
           this.workerArray.postMessage({workerName}, [channel.port1]);
           this.webWorkers[workerName].postMessage({data}, [channel.port2]);
           i++;
           }
           this.workerArray.onmessage = handleResults;
           }
           search = (searchTerm) => {
           this.workerArray.postMessage({searchTerm});
           }
           terminate() {
           this.workerArray.terminate();
           for (const workerName in this.webWorkers) {
           this.webWorkers[workerName].terminate();
           }
           }
          }
          


          WorkerArrayController用4個ww初始化workerArray web worker,并傳遞MessageChannel端口給它們,這樣它們能夠互相通信。

          //workerArray.js
          const ports = {};
          let cache = {};
          let queue;
          function initiatePort (workerName, port) {
           ports[workerName] = port;
           const webWorker = ports[workerName];
           webWorker.inUse = false;
           webWorker.onmessage = function handleResults (e) {
           const {searchTerm, searchResults} = e.data;
           const message = {searchTerm, searchResults};
           /* If all workers happen to be inUse, the message gets saved to the
           the queue and passed to the first worker that finishes */
           if(queue) {
           webWorker.postMessage(queue);
           webWorker.inUse = true;
           queue = null;
           } else {
           webWorker.inUse = false;
           }
           cache[searchTerm] = message;
           self.postMessage(message);
           }
          }
          function dispatchSearchRequest (searchTerm) {
           const cachedResult = cache[searchTerm];
           if(cachedResult) {
           self.postMessage(cachedResult);
           return
           }
           const message = {searchTerm};
           for (const workerName in ports) {
           const webWorker = ports[workerName];
           if(!webWorker.inUse) {
           webWorker.postMessage(message);
           webWorker.inUse = true;
           return
           }
           }
           queue = message;
          }
          self.onmessage = function (e) {
           const {workerName, searchTerm} = e.data;
           if(workerName) {
           initiatePort(workerName, e.ports[0]);
           } else if(searchTerm) {
           dispatchSearchRequest(searchTerm);
           }
          }
          


          workerArray初始化端口對象用于通信,并跟蹤每個ww worker。它還初始化了緩存和隊列,萬一所有端口都被占用的情況下用來跟蹤最新的searchTerm請求。

          //ww1.js
          self.importScripts('...the search engine script, provides the SearchEngine constructor');
          let searchEngine;
          let port;
          function initiate (data, port) {
           searchEngine = new SearchEngine(data);
           port = port;
           port.onmessage = search;
          }
          /* search is attached to the port as the message handler so it
          runs when communicating with the workerArray only */
          function search (e) {
           const {searchTerm} = e.data;
           const message = {
           searchResults: searchEngine.search(searchTerm)
           };
           port.postMessage(message)
          }
          /* self.onmessage is the handler that responds to messages from
          the main thread, which only fires during initiation */
          self.onmessage = function(e) {
           const {data} = e.data;
           initiate(data, e.ports[0]);
          }
          


          原文:Secrets of JavaScript: A tale of React, performance optimization and multi-threading

          本文為 CSDN 翻譯,轉載請注明來源出處。


          主站蜘蛛池模板: 在线观看精品视频一区二区三区 | 日本精品一区二区三区四区| 搜日本一区二区三区免费高清视频| AV鲁丝一区鲁丝二区鲁丝三区| 亚洲国产精品一区| 中文字幕Av一区乱码| 精品国产日产一区二区三区| 成人无码AV一区二区| 久久精品一区二区三区资源网| 亚洲AV无码一区二区乱子伦| 波多野结衣一区视频在线| 欧洲精品码一区二区三区| 一区二区三区四区无限乱码 | 女女同性一区二区三区四区| 日本免费一区二区三区最新vr| 国产成人精品亚洲一区| 久久久久女教师免费一区| 亚洲综合一区二区国产精品| 伊人久久精品一区二区三区| 精品成人一区二区三区免费视频| 日本片免费观看一区二区| 人妻无码一区二区三区四区| 中文字幕一区二区人妻性色| 久久精品亚洲一区二区三区浴池| 午夜在线视频一区二区三区| 中文字幕一区二区免费| 亚洲一区二区三区高清在线观看| 一区二区三区在线播放视频| 无码国产精成人午夜视频一区二区| 日本国产一区二区三区在线观看| 国产精品被窝福利一区| 国产福利一区二区三区视频在线| 精品一区二区三区在线视频观看| 国产成人一区二区三区在线观看| 在线一区二区观看| 亚洲国产一区二区a毛片| 日本一区二区三区精品国产| 日本成人一区二区| 麻豆精品一区二区综合av| 88国产精品视频一区二区三区| 国产成人精品一区在线|