植物煉金術:南太平洋雨林的樹會流出鎳金屬_網頁設計公司

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

透過資料庫的網站架設建置,建立公司的形象或購物系統,並提供最人性化的使用介面,讓使用者能即時接收到相關的資訊

摘錄自2018年09月06日地球圖輯隊報導

南太平洋的新喀里多尼亞(New Caledonia),當地的土壤環境含有鉻、鎳、錳等重金屬。為了要在這樣的環境下生存,當地的植物已發展出可吸收土壤重金屬的能力,流出來的樹脂也都含有重金屬。

在新喀里多尼亞,這裡至少有 65 種植物可直接從土壤吸收鎳金屬,其中最吸引研究人員注意的是學名為 Pycnandra acuminata 的樹,它是目前科學家發現能儲存最高鎳濃度的植物。這種樹,樹脂呈現非常特別的藍綠色,研究人員發現樹脂之所以會呈現藍綠色,正因成分含有 25% 的鎳。

※想知道最厲害的網頁設計公司嚨底家"!

RWD(響應式網頁設計)是透過瀏覽器的解析度來判斷要給使用者看到的樣貌

一些科學家認為,如果未來能利用這些重金屬高累積性植物,淨化受重金屬污染的土壤,或許就能解決人為重金屬污染問題。採礦業者則從重金屬高累積性植物看到商機。
 

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

當全世界的人們隨著網路時代而改變向上時您還停留在『網站美醜不重要』的舊有思維嗎?機會是留給努力改變現況的人們,別再浪費一分一秒可以接觸商機的寶貴時間!

小米11 官方拆解影片釋出,輕薄機身如何收納 S888 處理器、Harman Kardon 調音立體雙揚聲器?透過影片快速揭秘_網頁設計公司

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

以設計的實用美學觀點,規劃出舒適、美觀的視覺畫面,有效提昇使用者的心理期待,營造出輕鬆、愉悅的網站瀏覽體驗。

去年底小米推出全球首款搭載高通最新 Snapdragon 888 處理器的旗艦 5G 手機「小米11」,這次小米11 除了機身比起上一代更輕薄,而如何收納 Snapdragon 888 處理器、4600mAh 大電量電池、 Harman Kardon 調音的立體聲雙揚聲器也是許多人所關心的問題。另外,小米這次除了搭載 VC 液冷散熱系統,更添加奈米隔熱材料以優化手機的熱傳導路徑。

小米11 官方拆解影片釋出,輕薄機身如何收納 S888 處理器、Harman Kardon 調音立體雙揚聲器?透過影片快速揭秘

為了讓眾人快速理解小米11 的設計,官方在近日也上傳了一段官方版的拆機影片,讓大家能以最簡單的方式快速理解小米11 的機身內部的設計重點。

拆開機身背板首先看到的是無線充電線圈,小米11 支持最高 50W 無線快充:

接著是主相機模組,小米11 搭載 1 億像素三鏡頭主相機,依序為 1.08 億像素主鏡頭採用 1/1.33″ 超大感光元件、支持四合一 1.6μm 大像素輸出、7P鏡片以及 f/1.85 大光圈, 1300 萬像素 f/2.4 光圈的 123° 超廣角鏡頭以及 500 萬像素長焦微距鏡頭的組合。

小米11 搭載 Qualcomm Snapdragon 888 處理器搭配 LPDDR5 3000MHz RAM 和 UFS 3.1 ROM :

揚聲器也是這次小米11 的一大特色,採用與知名音響大廠 Harman Kardon 專業調音的立體聲雙揚聲器:

電量方面,小米11 內建 4600mAh 大容量電池,小米11 支持的 55W 有線快充可在 45 分鐘充電至 100% :

震動回饋這次在小米11 內建大尺寸 X 軸線性馬達:

關於小米11 的散熱細節,小米官方解釋小米11 採用了目前最頂級的手機散熱材料,不僅擁有大面積的液冷 VC 均熱板,螢幕、音腔、主板等主要發熱區域還覆蓋了大量石墨、銅箔、導熱凝膠等組成立體散熱系統。
另外,小米11 更在散熱路徑的優化用全新的隔熱材料—「奈米氣凝膠」。通過「一疏一堵」的組合,讓散熱過程中的熱傳遞更合理,高效散熱的同時手感溫和不燙手。

小米官方表示,消費者普遍認為手機散熱只需簡單的導熱足夠好即可。然而,其實手機的發熱量是相對恆定、相對不可調整的,但熱傳遞的路徑是可通過熱設計進行優化。在手機內部 Z 軸的空間最短、X 軸空間較長,而 Y 軸空間則最充裕,在輕薄的手機上 Z 軸的空間更加侷促(可參考下方小米製作的示意圖)。
倘若只是盲目追求加速熱傳遞,局部熱量將沿著 Z 軸方向快速傳遞到手機表面,這反而會讓手機摸起來更燙手,造成手機發熱嚴重的錯覺、削減甚至隔斷 Z 軸空間的熱傳導能力。讓局部元器件發熱更多向 X 軸和 Y 軸的方向傳導,則能做到迅速散熱的同時,還兼顧觸摸手感。

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網站的第一印象網頁設計,決定了客戶是否繼續瀏覽的意願。台北網動廣告製作的RWD網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上它。

因此,小米也在小米11 嘗試採用全新的隔熱材料奈米氣凝膠,藉此隔斷手機發熱沿 Z 軸的傳導通道、阻斷了內部熱源與手機表面之間的傳遞路徑。阻隔的這部分熱量,通過小米11 內部的立體散熱系統在 X 軸和 Y 軸傳導,這樣既解決局部發熱的問題保證晶片的正常工作,又避免了局部的單點發熱還沒來得及均熱,就過早被手掌感知。

奈米氣凝膠類似於羽絨衣的隔熱原理,內部由二氧化矽為主的有機分子骨架,可將空氣包裹在骨架的空間,空氣含量高達 97% 以上,就像一個微型的羽絨服。空氣層導熱率極低,能夠提供很好的隔熱能力。而且輕薄的結構特性,也讓奈米氣凝膠擁有極佳的隔熱性能的同時,也滿足了手機輕薄的需求 。

這次小米11 另一項有感升級則是將機身變得更輕薄,其中原因之一也包括採用超薄螢幕下指紋辨識,這次指紋感應器更支持心律檢測功能:

圖片/消息來源:小米手機(微博)

完整影片

 

延伸閱讀:
小米 10i 5G 印度發表:搭載高通 750G 5G 處理器、1.08 億像素主相機、 120Hz更新率螢幕與 4820mAh 大電量

HTC Desire 21 Pro 5G 實機諜照流出!配備 4800 萬像素四鏡頭主相機、支持雙卡雙待

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

台中景泰電動車行只是一個單純的理由,將來台灣的環境,出門可以自由放心的深呼吸,讓空氣回歸自然的乾淨,減少污染,留給我們下一代有好品質無空污的優質環境

新一代 LG Gram 輕薄筆記型電腦發表,全系列 11 代 Intel Core 處理器上身_網頁設計公司

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

當全世界的人們隨著網路時代而改變向上時您還停留在『網站美醜不重要』的舊有思維嗎?機會是留給努力改變現況的人們,別再浪費一分一秒可以接觸商機的寶貴時間!

LG Gram 筆記型電腦從推出一來以超乎想像的輕盈著稱,日前,2021 年最新款系列陣容發表,這次的重點在於部分設計的改良以及內部規格的升級。在新一代中總共包含五種機型,其中包含三款翻蓋式筆電 Gram 17、Gram 16、Gram 14 以及兩款翻轉式 Gram 2in 1 16 與 Gram 2 in 1 14。

新一代 LG Gram 輕薄筆記型電腦發表,11 代 Intel Core 處理器上身

最新的陣容還是延續 Gram 的招牌特色,以驚人的輕盈纖瘦讓人讚嘆。最大的機型 Gram 17 只有 2.98 磅(約合 1.35 公斤),重量與其前代相同,而 Gram 16 僅有 2.62 磅(約合 1.19 公斤),Gram 14 則僅有 2.2 磅(約合 0.99 公斤)。2021 年款的 Gram 17 採用與 2020 年款一樣的外型,其 16:10 顯示器比傳統的 16:9 提供更多的垂直空間。此外,LG 表示,新的翻蓋式機型在設計上擁有四面超窄邊框,實現 90% 的螢幕佔比。

2021 年款的 LG Gram 在鍵盤與觸控板部分加大,提高使用的舒適度與工作效率,讓使用者打字更輕鬆快速。最重要的升級在配備方面,所有最新型號的 LG Gram 皆配備 Intel 第 11 代 Core 處理器,可配置 Iris Xe 或 UHD 顯卡,全機種皆通過 Intel Evo 認證,代表全系列機型擁有至少 9 小時續航力,一秒喚醒等能力。LG 官方表示,在 Gram 17、Gram 16 與 Gram 2in 1 16 上最長續航力可以達到 19.5 小時。

雖然目前價格與上市時間未定,但如果你特別喜歡輕薄筆電,從之前歷代 LG Gram 的表現看來新一代讓人感到非常期待。

※想知道最厲害的網頁設計公司嚨底家"!

RWD(響應式網頁設計)是透過瀏覽器的解析度來判斷要給使用者看到的樣貌

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

透過資料庫的網站架設建置,建立公司的形象或購物系統,並提供最人性化的使用介面,讓使用者能即時接收到相關的資訊

realme V15 正式發表:176 克輕盈重量、50W 智慧閃充並標配 65W 閃充充電器,售價僅約 6,450 元起_網頁設計公司

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

搬家費用:依消費者運送距離、搬運樓層、有無電梯、步行距離、特殊地形、超重物品等計價因素後,評估每車次單

日前 realme 在台灣開賣 realme X7 Pro 以及 realme 7 5G 兩款新機,最近也預告將在中國率先發表 realme V 系列的新機 realme V15 。今(7)日稍早 realme 舉辦 2021 年智慧型手機市場的首場新機發表會推出 realme V15 ,除了價格和性能持續「敢越級」,在機身設計也有許多巧思。
realme 也「響應環保」直接附贈 65W 超級閃充充電器給 50W 智慧閃充的 V15 消費者,讓全家人都能用這款充電器進行快速充電。

realme V15 正式發表:176 克輕盈重量、50W 智慧閃充並標配 65W 閃充充電器,售價僅約 6,450 元起

作為 realme 旗下以「續航越級」為核心的 realme V 系列新機, realme V15 除了在續航方面持續越級,也針對性能、快充、設計等方面相較上一代進行全面升級。首先是機身設計, realme V15  機身厚度僅有 8.1mm 、重量也只有 176 克,機身表面的工藝處理也是這次的一大亮點。

外觀配色方面,這次 realme V15 總共推出「錦鯉色」、「鏡湖藍」以及「新月銀」三款配色選擇。首先是「錦鯉色」採用非光譜漸變的色彩設計以及雙紋雙鍍工藝,營造奪目溫暖、具有流動感的錦鯉色彩。

另外,在「鏡湖藍」以及「新月銀」則擁有鏡面級高反光和細膩磨砂的兩種質感處理。

realme V15 在螢幕方面採用 6.4 吋 SuperAMOLED 挖孔全螢幕,擁有 600nit 峰值亮度和 180Hz 觸控採樣率,並採用類DC調光護眼螢幕且支持光感螢幕下指紋辨識:

相較於之前的 LCD 螢幕, realme V15 改用 OLED 螢幕除了讓機身能更輕薄、也支持螢幕指紋解鎖、AOD(Always On Display)顯示,無論對於日常使用解鎖或觀看時間、未讀訊息都更加便利:

硬體規格方面, realme V15 與之前在台灣開賣不久的 realme 7 5G 一樣搭載聯發科 800U 5G 處理器,在性能方面相較上一代提升 16% ,安兔兔跑分也超過 34 萬分的成績:

在這僅 8.1mm 厚度的機身條件下, realme V15 仍配備 4310mAh 大容量電池,同時也支持和 realme X7 Pro 一樣等級的 50W SuperDART 智慧閃充,只需要 18 分鐘即可為 realme V15 充電至 50% :

在充電速度方面, realme V15 只需 47 分鐘充滿優於在同價位機型的充電速度,相比其他品牌更高瓦數快充的旗艦手機表現也不遜色:

最近小米跟隨 Apple 響應環保開始在小米11 推出取消充電器的標準版,卻另外推出相同價格附贈充電器的套裝版的方式,也引起許多討論。而 realme 在稍早 V15 發表會則提出另一種響應環保的方法,那就是「讓全家人都可以共用一款充電器」。
畢竟家中不同成員可能使用不同快充功率規格的智慧型手機,因此 realme V15 即便是 50W 智慧閃充,仍然標配提供 65W 閃充充電器。

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

透過選單樣式的調整、圖片的縮放比例、文字的放大及段落的排版對應來給使用者最佳的瀏覽體驗,所以不用擔心有手機版網站兩個後台的問題,而視覺效果也是透過我們前端設計師優秀的空間比例設計,不會因為畫面變大變小而影響到整體視覺的美感。

充電快,在續航方面 realme V15 透過全場景續航優化,即便剩餘電量只剩下 5% 仍可待機一天一夜。

影像方面, realme V15 配備 6400 萬像素三鏡頭主相機,分別為 6400 萬像素主鏡頭、 800 萬像素 119° 超廣角鏡頭以及 4cm 微距鏡頭的組合,前置相機則採用 1600 萬素自拍鏡頭。錄影部分, realme V15 不僅支持最高 4K@30fps 的高畫質錄影,前後鏡頭皆支持 UIS MAX 錄影超級防手震。

拍攝也支持超級夜景模式,連同自拍也支持超級夜景,在全場景皆可實現更優異的夜拍成果。之前在 realme X7 Pro 和 realme 7 5G 內建的夜景濾鏡,在 realme V15 同樣有支援。

realme V15 推出 6GB+128GB 和 8GB+128GB 兩種規格選擇, 6GB+128GB 版本建議售價人民幣 1,499 元(約合新台幣 6,450 元);8GB+128GB 版本建議售價人民幣 1,999 元(約合新台幣 8,606 元),目前在首批在中國開賣的 realme V15 入門版將以降價人民幣 100 元的方式促銷。

圖片/消息來源:realme(中國官網)|realme 真我手機(微博)

延伸閱讀:
realme 7 5G 開箱動手玩|天璣 800U 處理器、5G+5G 雙卡雙待、120Hz 更新率螢幕、5000mAh大電量與 30W Dart 閃充,萬元內 5G 超值選擇

疑似 OPPO Find X3 安兔兔跑分曝光,搭載高通 S888 旗艦處理器測出 77.1 萬分刷新最高分紀錄

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

節能減碳愛地球是景泰電動車的理念,是創立景泰電動車行的初衷,滿意態度更是服務客戶的最高品質,我們的成長來自於你的推薦。

讀懂操作系統之虛擬內存地址翻譯原理分析篇(二)_網頁設計公司

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

以設計的實用美學觀點,規劃出舒適、美觀的視覺畫面,有效提昇使用者的心理期待,營造出輕鬆、愉悅的網站瀏覽體驗。

前言

上一節我們整體概括通過MMU將虛擬地址翻譯為物理地址的轉換,這個過程都是按序就班的進行,一切都是基於已提前創建、分配虛擬頁、物理頁以及命中的前提,只是給和我一樣沒怎麼系統學習操作系統的童鞋首先在腦海里有個大概的印象,本節我們從源頭開始分析為程序創建進程到映射到主存上整個詳細過程,本文將通過大量圖解來分析原理,以便讓各位能夠完全理解地址翻譯原理。若有敘述不當之處,還請批評指正。 

虛擬內存原理分析

如果沒有系統學習現代操作系統,理論上我們會認為用戶程序會將內存視為單個連續的內存空間,實際上可以將用戶程序在內存中分佈可以分散在頁面的整個物理內存中。分頁是一種內存管理方案,它允許進程的物理地址空間不連續。

物理內存劃分:將物理內存劃分為稱為幀的固定大小的塊(大小為2的冪,介於512字節和16 MB之間,必須跟蹤所有空閑幀)

虛擬(邏輯)內存劃分:將邏輯內存分成大小相同的塊(稱為頁,每一塊也是分為相同大小的頁面)

若要運行大小為N頁的程序,需要找到N個空閑幀並加載程序

地址翻譯方案

通過常駐內存中的頁表將虛擬地址翻譯為物理地址, CPU生成的虛擬地址被劃分為虛擬頁號(用作頁表索引,該頁表包含物理內存中每個頁的基地址)和虛擬頁偏移量(與基址結合找到存儲單元的物理存儲地址)。對於給定的邏輯地址空間2m和頁面大小2n,如下:

分頁內存管理方案本質就是通過MMU將CPU產生的虛擬地址通過中間媒介(頁表)進行地址翻譯,如下為簡單翻譯版本,一目瞭然。

上述我們學習了將邏輯地址(虛擬地址)劃分為頁號(注意:頁號並不屬於頁表的一部分,頁號不儲存在主存)和頁偏移量,到底是怎樣藉助頁號和頁偏移量進行翻譯的呢?我們舉個例子:假設如下一個32字節的物理內存,邏輯地址空間為16字節,說明邏輯地址有4位,而頁幀偏移量為4個字節,因頁幀偏移量和虛擬頁偏移量相等,所以虛擬頁偏移量也為4個字節即2位,所以頁號為(4-2)= 2位即邏輯地址共有4頁,如此假設和實際理論計算對等。地址翻譯如下:

若CPU要找出邏輯地址為4的物理地址,通過上述我們知道邏輯地址為4在第1頁且偏移量為0,然後去查找頁表索引等於1的頁幀號為6,因為物理地址 = (frame * pageSize)+ offset,所以邏輯地址4的物理地址=(6 * 4 bytes)+ 0 byte offset = 24。同理,比如如上邏輯地址為7在第1頁,偏移量為3對應頁表上的幀6,所以其物理地址為:(6 * 4 bytes)+ 3 byte offset = 27,這裏需要注意的是物理地址的偏移量是相對這頁的起始位置偏移。通過上述圖解,我們反推根據邏輯地址和每頁字節大小計算出其所在頁和偏移量(下面根據虛擬地址計算虛擬頁號和偏移量會用到),比如邏輯地址為7,因每頁大小為4個字節,則所在頁為(7 / 4) = 1,偏移量(7 mod / 4) = 3。

擴展頁表條目(PTE)信息

現代計算機頁表上的條目除了包含將虛擬地址翻譯為虛擬地址的主要信息(有效位、頁號)外,其中還包含如下其他信息(下面講解頁面置換算法會用到):

保護位(Protection):控制對指定虛擬頁的訪問是否可讀、可寫、可執行

引用位(Refrence):為了近似實現LRU算法,幫助操作系統估算最近最少使用的頁,當一頁被訪問時該位將被置位,操作系統定期將引用位清零,然後重新記錄,這樣就可以判定在這段特定時間內哪些頁被訪問過,通過檢查引用位是否關閉,操作系統就可以從那些最近最少訪問的頁中選擇一頁

臟位(Modify):當某一頁被替換時,操作系統需要知道該頁是否需要被複制寫回,為了追蹤讀入主存中的頁是否被寫過,增加一個臟位,當頁中任何字被寫時就將這一位置位。如果操作系統選擇替換某一頁,臟位指明了把該頁所佔用的主存讓給另一頁之前,是否需要將該頁寫回磁盤,因此,一個被修改的頁通常被稱為臟頁。

TLB緩存頁表

上一節我們講過CPU產生邏輯地址后通過MMU轉換為物理地址時,每次都要訪問頁表,訪問緩存和主存的時間相差上百個時鐘周期,所以為了提高查找性能則使用TLB,我們可認為TLB是實現頁表最好的方式,本質上是緩存頁表。在沒有TLB作為緩存時,我們使用頁號(VPN)作為索引去頁表上查找物理頁號,引入TLB后,將頁號劃分為TLBT(TLB標記)和TLBI(TLB索引)只是做了一下轉換而已,TLBI佔2位,剩餘的位就是TLBT。下面會通過一個實際例子來講解如何結合TLBT和TLBI在TLB上查找。

 

TLB作為頁表的緩存,用於存放映射到頁幀中的那些項,TLB包含了頁表中虛擬頁到頁幀映射的一個子集,因為將其作為緩存,所以額外還存在如上一個標記區域(TLBT),換句話說頁表不同於TLB並不是作為緩存,所以並不需要標記區域,再加上如上額外的PTE擴展信息,所以TLB的存儲結構如下:

TLB缺失

接下來我們開始進入TLB缺失環節,我們假設虛擬地址有14位,物理地址有16位,每頁大小有64個字節,那麼虛擬地址空間和物理地址空間如下圖所示

因為每頁大小為64字節即(26),同時虛擬頁偏移量和頁幀偏移量相等,所以虛擬頁偏移量和頁幀偏移量都為6位,那麼將虛擬地址空間和物理地址空間劃分為對應的頁號和頁偏移量則如下圖所示:

接下來則是將虛擬頁號劃分為TLBT和TLBI,因為TLB包含16個條目且4路關聯,那麼說明有S =(16 / 4)= 4組,那麼TLBI佔位 =  log2S = 2,剩餘的則是TLBT = (8 – 2) = 6位,如下圖所示

現在我們對虛擬地址和物理地址都有了完整的劃分,現在假設TLB和頁表狀態存儲結構分別如下圖

 

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

台中景泰電動車行只是一個單純的理由,將來台灣的環境,出門可以自由放心的深呼吸,讓空氣回歸自然的乾淨,減少污染,留給我們下一代有好品質無空污的優質環境

假設現在CPU產生一個虛擬地址(0x0334),首先我們需要將其轉換為虛擬頁號(VPN),因每個頁面大小為64字節,所以計算方式如下代碼

var xvpn = Convert.ToInt32("0x334", 16);
var vpn = xvpn / 64; //vpn = 12
var vpo = xvpn % 64; //vpo = 52

上述計算出VPN等於12,然後將其對應虛擬地址上的VPN和VPO用二進製表示,分別如下圖所示

而存儲在TLB和頁表上的狀態都是16進制,所以上述VPN = 1210 = 0x0C16和VPO = 5210 = 0x3416,到此已經劃分完VPN和VPO,接下來則是將VPN劃分為TLBT和TLBI,由上述我們已經知道TLBT和TLBI在VPN中所佔位數,所以如下圖所示

由上我們可得出TLBT = 310 = 0x0316,而TLBI = 0,有了TLBT(0x03)和TLBI(0)再去查找TLB狀態表,如下紅色標記

由上圖我們發現此時標誌無效而且物理頁號也沒有,此時發生TLB缺失,於是通過MMU將虛擬地址得到的VPN去頁表中查找

此時我們看到在頁表中也缺失,所以這裏將發生缺頁異常。TLB缺失分為如下兩種情況

頁在主存(頁表)中,只需要創建缺失的TLB表項

頁不在主存(頁表)中,需要將控制權交給操作系統來解決缺頁 

TLB缺失既可以通過軟件處理也可以通過硬件處理,比如MIPS、Alpha通過軟件處理TLB缺失,x86、ARM通過硬件處理TLB缺失,兩種處理方式在性能差別上很小,無論哪一種方式需要執行的基本操作都是一樣的。理論上來講,在進程分配頁幀時會將對應頁幀更新到頁表上,但是上述情況並未在主存頁表中說明在頁幀列表中沒有空閑的頁幀,所以這是TLB缺失中真正的缺頁情況,此時將觸發缺頁異常,控制權交給操作系統內核中的缺頁異常處理程序,操作系統知道了引起缺頁的虛擬地址,操作系統必須完成以下3個步驟:【1】使用虛擬地址查找頁表項,並在磁盤上找到被訪問的頁的位置【2】選擇替換一個物理頁,如果該選中的頁被修改過,需要在把新的虛擬頁裝入之前將這個物理頁寫回磁盤,這一過程稱為頁面置換【3】啟動讀操作,將被訪問的頁從磁盤上取回到所選擇的物理頁的位置上【4】重新執行引發缺頁的那條指令。因為第3個步驟需要耗費數百萬個時鐘周期,如果第2個步驟中被替換的物理頁已被重寫過,那麼同樣也會花費這麼長時間,因此操作系統會選擇另外一個進程在處理器上執行直到磁盤訪問結束,所以前3個步驟執行所耗費的時間比較長,最後重新執行缺頁指令。若在頁表中找到了頁幀號(即頁在主存中),那說明TLB缺失只是一次轉換缺失,在這種情況下,CPU只需要將頁表項裝載到TLB並且重新訪問來進行缺失處理。

頁面置換算法

為了解決缺頁情況,所以必須實現頁面置換作為請求調頁的基礎,這裏我們介紹常見的幾種置換算法,分別是Optional or MIN algorithm、FIFO(First-In-First-Out)、Clock、LRU(Least Recently Used),針對各個算法,現假設有(1、2、3、4、1、2、5、1、2、3、4、5)12個引用串,4個空閑頁幀。

FIFO(先進先出)

該算法記錄了每個頁面記錄調到內存的時間,當必須置換頁面時,將選擇最舊的頁面,請注意,並不需要記錄調入頁面的確切時間,可以通過創建一個隊列實現此目的。具體過程太過簡單,這裏就不再細講,此時將發生10次缺頁錯誤,我們可計算出缺頁率為(10/12)= 83%。如下:

 

OPT or MIN(最優)

最優置換算法找出最長時間沒有使用的頁,具有最低缺頁率,可以用作離線分析方法,但是難以實現。此時將發生6次缺頁錯誤,我們可計算出缺頁率為(6/12)= 50%。如下:

 

LRU(最近最少使用)

FIFO算法使用的是頁面調入內存的時間,OPT算法使用的是頁面將來使用的時間,而LRU算法採用置換最長時間沒有的頁,該算法將每個頁面與它上次使用的時間關聯起來,當需要置換頁面時,LRU選擇最長時間沒有使用的頁面,該算法很難實現。此時將發生8次缺頁錯誤,我們可計算出缺頁率為(8/12)= 67%。如下:

啟動和切換進程

上述我們只是從已經將程序加載到內存中所創建的進程角度來分析如何將虛擬地址翻譯為物理地址,由於操作系統負責管理內存,因此必須了解物理內存的分配詳細信息,分配了哪些頁幀、每個頁幀分配個哪個進程的哪個頁面,哪些頁幀可用,總共有多少幀,對此我們還一無所知。將用戶程序加載到虛擬內存中的進程後為其劃分對應的虛擬頁,假設如下劃分了4個虛擬頁,操作系統在跟蹤的頁幀列表找出空閑(操作系統分配幀算法,這裏暫不討論)的頁幀分配給虛擬頁,然後操作系統再啟動進程。如下圖:

 

如上節所述頁表保存在主存中,當調度進程時通過頁表基址寄存器(PTBR)指向激活的指定進程頁表, 當然也會加載另外一個寄存器(程序計數器,PC),所以每個數據或指令訪問需要進行兩次主存訪問,一次是頁表,另一次則是用於數據或指令。

 

當進程希望以受限的方式共享信息時,操作系統必須對其進行協助,這是因為訪問另外一個進程的信息需要改變訪問進程的頁表,寫訪問位可以用來把共享限製為只讀,並且和頁表中其他位一樣,該位只能被操作系統所修改。為了允許另一進程,設為P1,去讀屬於進程P2的一頁,P2就要請求操作系統在P1地址空間中為一個虛擬頁生成頁表項,指向P2想要共享的物理頁。如果P2要求操作系統可以使用寫保護位以防止P1對數據進行改寫,由於只有TLB缺失才會訪問頁表,任何決定頁對的訪問權限不僅要包含在頁表中,還要包含在TLB中。當操作系統決定從進程P1切換到P2時,我們稱之為上下文切換,它必須保證P2不能P1的頁表,否則不利於數據保護,若沒有TLB,只需要把頁表基址寄存器指向P2的頁表而不是P1就夠了,如果有TLB,我們必須在其中清除屬於P1的表項,不僅僅是為了保護P1的數據,而且是為了迫使TLB裝入P2的表項。如果進程切換的頻率很高,那麼這一舉措效率將會很低。例如,在操作系統切回P1之前,P2可能只裝入了很少的TLB表項,但是,P1隨後發現它所有的表項都不見了,因此不得不通過TLB缺失來重新加載這些表項,產生這個問題的原因在於進程P1和P2使用同一虛擬地址空間,並且我們必須清除TLB以防止地址混淆。另一種常見的方法則是增加進程標識符和任務標識符來擴展虛擬地址空間,比如FastMATH就有8位地址空間標識域(ASID),這個標識域標識了當前正在運行的進程,當進程切換時,它保存在由操作系統裝入的寄存器中,進程標識符與TLB的標記部分相連接,因此只有在頁號和進程標識符相匹配時,TLB才會發生命中,如此一來,除非特殊情況,我們就不需要清除TLB。 說了怎麼多除了保護機制外,當我們切換進程時主要需要做哪些工作呢(即從一個進程控制塊(Process Control Block,PCB)切換到另一個進程塊,後續會深入講解操作系統線程和進程)?

切換頁表到當前PCB

頁表基址寄存器指向當前頁表

清除TLB,並將當前頁表項裝載到TLB(按需加載,進程訪問哪些頁才將對應頁表項加載到TLB)

留個作業

若TLB中的PTE條目達到上限即滿時,不難想象理論上會替換現有條目,那麼採取替換的策略或機制是怎樣的呢?

總結

基於上一節內容我們詳細講解了將虛擬地址翻譯為物理地址的具體過程、進程頁幀分配、頁面置換算法,在講解TLB缺失時並未涉及高速緩存,TLB和高速緩存將在下一節作為詳解。關於虛擬內存內容通過一兩篇文章根本講解不清楚,比如還有減少頁表容量方式、TLB和高速緩存關係、Intel和Linux虛擬內存系統等等。我盡量通過圖解方式來帶給大家較好的理解體驗,能夠更好的消化和吸收虛擬內存。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網站的第一印象網頁設計,決定了客戶是否繼續瀏覽的意願。台北網動廣告製作的RWD網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上它。

基於 abp vNext 和 .NET Core 開發博客項目 – 博客接口實戰篇(一)_網頁設計公司

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

透過資料庫的網站架設建置,建立公司的形象或購物系統,並提供最人性化的使用介面,讓使用者能即時接收到相關的資訊

系列文章

  1. 基於 abp vNext 和 .NET Core 開發博客項目 – 使用 abp cli 搭建項目
  2. 基於 abp vNext 和 .NET Core 開發博客項目 – 給項目瘦身,讓它跑起來
  3. 基於 abp vNext 和 .NET Core 開發博客項目 – 完善與美化,Swagger登場
  4. 基於 abp vNext 和 .NET Core 開發博客項目 – 數據訪問和代碼優先
  5. 基於 abp vNext 和 .NET Core 開發博客項目 – 自定義倉儲之增刪改查
  6. 基於 abp vNext 和 .NET Core 開發博客項目 – 統一規範API,包裝返回模型
  7. 基於 abp vNext 和 .NET Core 開發博客項目 – 再說Swagger,分組、描述、小綠鎖
  8. 基於 abp vNext 和 .NET Core 開發博客項目 – 接入GitHub,用JWT保護你的API
  9. 基於 abp vNext 和 .NET Core 開發博客項目 – 異常處理和日誌記錄
  10. 基於 abp vNext 和 .NET Core 開發博客項目 – 使用Redis緩存數據
  11. 基於 abp vNext 和 .NET Core 開發博客項目 – 集成Hangfire實現定時任務處理
  12. 基於 abp vNext 和 .NET Core 開發博客項目 – 用AutoMapper搞定對象映射
  13. 基於 abp vNext 和 .NET Core 開發博客項目 – 定時任務最佳實戰(一)
  14. 基於 abp vNext 和 .NET Core 開發博客項目 – 定時任務最佳實戰(二)
  15. 基於 abp vNext 和 .NET Core 開發博客項目 – 定時任務最佳實戰(三)
  16. 基於 abp vNext 和 .NET Core 開發博客項目 – 博客接口實戰篇(一)
  17. 基於 abp vNext 和 .NET Core 開發博客項目 – 博客接口實戰篇(二)
  18. 基於 abp vNext 和 .NET Core 開發博客項目 – 博客接口實戰篇(三)
  19. 基於 abp vNext 和 .NET Core 開發博客項目 – 博客接口實戰篇(四)
  20. 基於 abp vNext 和 .NET Core 開發博客項目 – 博客接口實戰篇(五)
  21. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(一)
  22. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(二)
  23. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(三)
  24. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(四)
  25. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(五)
  26. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(六)
  27. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(七)
  28. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(八)
  29. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(九)
  30. 基於 abp vNext 和 .NET Core 開發博客項目 – 終結篇之發布項目

從本篇就開始博客頁面的接口開發了,其實這些接口我是不想用文字來描述的,太枯燥太無趣了。全是CRUD,誰還不會啊,用得着我來講嗎?想想為了不半途而廢,為了之前立的Flag,還是咬牙堅持吧。

準備工作

現在博客數據庫中的數據是比較混亂的,為了看起來像那麼回事,顯得正式一點,我先手動搞點數據進去。

搞定了種子數據,就可以去愉快的寫接口了,我這裏將根據我現在的博客頁面去分析所需要接口,感興趣的去點點。

為了讓接口看起來清晰,一目瞭然,刪掉之前在IBlogService中添加的所有接口,將5個自定義倉儲全部添加至BlogService中,然後用partial修飾。

//IBlogService.cs
public partial interface IBlogService
{
}

//BlogService.cs
using Meowv.Blog.Application.Caching.Blog;
using Meowv.Blog.Domain.Blog.Repositories;

namespace Meowv.Blog.Application.Blog.Impl
{
    public partial class BlogService : ServiceBase, IBlogService
    {
        private readonly IBlogCacheService _blogCacheService;
        private readonly IPostRepository _postRepository;
        private readonly ICategoryRepository _categoryRepository;
        private readonly ITagRepository _tagRepository;
        private readonly IPostTagRepository _postTagRepository;
        private readonly IFriendLinkRepository _friendLinksRepository;

        public BlogService(IBlogCacheService blogCacheService,
                           IPostRepository postRepository,
                           ICategoryRepository categoryRepository,
                           ITagRepository tagRepository,
                           IPostTagRepository postTagRepository,
                           IFriendLinkRepository friendLinksRepository)
        {
            _blogCacheService = blogCacheService;
            _postRepository = postRepository;
            _categoryRepository = categoryRepository;
            _tagRepository = tagRepository;
            _postTagRepository = postTagRepository;
            _friendLinksRepository = friendLinksRepository;
        }
    }
}

在Blog文件夾下依次添加接口:IBlogService.Post.csIBlogService.Category.csIBlogService.Tag.csIBlogService.FriendLink.csIBlogService.Admin.cs

在Blog/Impl文件夾下添加實現類:IBlogService.Post.csBlogService.Category.csBlogService.Tag.csBlogService.FriendLink.csBlogService.Admin.cs

同上,.Application.Caching層也按照這個樣子添加。

注意都需要添加partial修飾為局部的接口和實現類,所有文章相關的接口放在IBlogService.Post.cs中,分類放在IBlogService.Category.cs,標籤放在IBlogService.Tag.cs,友鏈放在IBlogService.FriendLink.cs,後台增刪改所有接口放在IBlogService.Admin.cs,最終效果圖如下:

文章列表頁

分析:列錶帶分頁,以文章發表的年份分組,所需字段:標題、鏈接、時間、年份。

.Application.Contracts層Blog文件夾下添加返回的模型:QueryPostDto.cs

//QueryPostDto.cs
using System.Collections.Generic;

namespace Meowv.Blog.Application.Contracts.Blog
{
    public class QueryPostDto
    {
        /// <summary>
        /// 年份
        /// </summary>
        public int Year { get; set; }

        /// <summary>
        /// Posts
        /// </summary>
        public IEnumerable<PostBriefDto> Posts { get; set; }
    }
}

模型為一個年份和一個文章列表,文章列表模型:PostBriefDto.cs

//PostBriefDto.cs
namespace Meowv.Blog.Application.Contracts.Blog
{
    public class PostBriefDto
    {
        /// <summary>
        /// 標題
        /// </summary>
        public string Title { get; set; }

        /// <summary>
        /// 鏈接
        /// </summary>
        public string Url { get; set; }

        /// <summary>
        /// 年份
        /// </summary>
        public int Year { get; set; }

        /// <summary>
        /// 創建時間
        /// </summary>
        public string CreationTime { get; set; }
    }
}

搞定,因為返回時間為英文格式,所以CreationTime 給了字符串類型。

IBlogService.Post.cs中添加接口分頁查詢文章列表QueryPostsAsync,肯定需要接受倆參數分頁頁碼和分頁數量。還是去添加一個公共模型PagingInput吧,在.Application.Contracts下面。

//PagingInput.cs
using System.ComponentModel.DataAnnotations;

namespace Meowv.Blog.Application.Contracts
{
    /// <summary>
    /// 分頁輸入參數
    /// </summary>
    public class PagingInput
    {
        /// <summary>
        /// 頁碼
        /// </summary>
        [Range(1, int.MaxValue)]
        public int Page { get; set; } = 1;

        /// <summary>
        /// 限制條數
        /// </summary>
        [Range(10, 30)]
        public int Limit { get; set; } = 10;
    }
}

Page設置默認值為1,Limit設置默認值為10,Range Attribute設置參數可輸入大小限制,於是這個分頁查詢文章列表的接口就是這個樣子的。

//IBlogService.Post.cs
public partial interface IBlogService
{
    /// <summary>
    /// 分頁查詢文章列表
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    Task<ServiceResult<PagedList<QueryPostDto>>> QueryPostsAsync(PagingInput input);
}

ServiceResultPagedList是之前添加的統一返回模型,緊接着就去添加一個分頁查詢文章列表緩存接口,和上面是對應的。

//IBlogCacheService.Post.cs
using Meowv.Blog.Application.Contracts;
using Meowv.Blog.Application.Contracts.Blog;
using Meowv.Blog.ToolKits.Base;
using System;
using System.Threading.Tasks;

namespace Meowv.Blog.Application.Caching.Blog
{
    public partial interface IBlogCacheService
    {
        /// <summary>
        /// 分頁查詢文章列表
        /// </summary>
        /// <param name="input"></param>
        /// <param name="factory"></param>
        /// <returns></returns>
        Task<ServiceResult<PagedList<QueryPostDto>>> QueryPostsAsync(PagingInput input, Func<Task<ServiceResult<PagedList<QueryPostDto>>>> factory);
    }
}

分別實現這兩個接口。

//BlogCacheService.Post.cs
public partial class BlogCacheService
{
    private const string KEY_QueryPosts = "Blog:Post:QueryPosts-{0}-{1}";

    /// <summary>
    /// 分頁查詢文章列表
    /// </summary>
    /// <param name="input"></param>
    /// <param name="factory"></param>
    /// <returns></returns>
    public async Task<ServiceResult<PagedList<QueryPostDto>>> QueryPostsAsync(PagingInput input, Func<Task<ServiceResult<PagedList<QueryPostDto>>>> factory)
    {
        return await Cache.GetOrAddAsync(KEY_QueryPosts.FormatWith(input.Page, input.Limit), factory, CacheStrategy.ONE_DAY);
    }
}
//BlogService.Post.cs
/// <summary>
/// 分頁查詢文章列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<ServiceResult<PagedList<QueryPostDto>>> QueryPostsAsync(PagingInput input)
{
    return await _blogCacheService.QueryPostsAsync(input, async () =>
    {
        var result = new ServiceResult<PagedList<QueryPostDto>>();

        var count = await _postRepository.GetCountAsync();

        var list = _postRepository.OrderByDescending(x => x.CreationTime)
                                  .PageByIndex(input.Page, input.Limit)
                                  .Select(x => new PostBriefDto
                                  {
                                      Title = x.Title,
                                      Url = x.Url,
                                      Year = x.CreationTime.Year,
                                      CreationTime = x.CreationTime.TryToDateTime()
                                  }).GroupBy(x => x.Year)
                                  .Select(x => new QueryPostDto
                                  {
                                      Year = x.Key,
                                      Posts = x.ToList()
                                  }).ToList();

        result.IsSuccess(new PagedList<QueryPostDto>(count.TryToInt(), list));
        return result;
    });
}

PageByIndex(...)TryToDateTime().ToolKits層添加的擴展方法,先查詢總數,然後根據時間倒序,分頁,篩選出所需字段,根據年份分組,輸出,結束。

BlogController中添加API。

/// <summary>
/// 分頁查詢文章列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet]
[Route("posts")]
public async Task<ServiceResult<PagedList<QueryPostDto>>> QueryPostsAsync([FromQuery] PagingInput input)
{
    return await _blogService.QueryPostsAsync(input);
}

[FromQuery]設置input為從URL進行查詢參數,編譯運行看效果。

※想知道最厲害的網頁設計公司嚨底家"!

RWD(響應式網頁設計)是透過瀏覽器的解析度來判斷要給使用者看到的樣貌

已經可以查詢出數據,並且緩存至Redis中。

獲取文章詳情

分析:文章詳情頁,文章的標題、作者、發布時間、所屬分類、標籤列表、文章內容(HTML和MarkDown)、鏈接、上下篇的標題和鏈接。

創建返回模型:PostDetailDto.cs

//PostDetailDto.cs
using System.Collections.Generic;

namespace Meowv.Blog.Application.Contracts.Blog
{
    public class PostDetailDto
    {
        /// <summary>
        /// 標題
        /// </summary>
        public string Title { get; set; }

        /// <summary>
        /// 作者
        /// </summary>
        public string Author { get; set; }

        /// <summary>
        /// 鏈接
        /// </summary>
        public string Url { get; set; }

        /// <summary>
        /// HTML
        /// </summary>
        public string Html { get; set; }

        /// <summary>
        /// Markdown
        /// </summary>
        public string Markdown { get; set; }

        /// <summary>
        /// 創建時間
        /// </summary>
        public string CreationTime { get; set; }

        /// <summary>
        /// 分類
        /// </summary>
        public CategoryDto Category { get; set; }

        /// <summary>
        /// 標籤列表
        /// </summary>
        public IEnumerable<TagDto> Tags { get; set; }

        /// <summary>
        /// 上一篇
        /// </summary>
        public PostForPagedDto Previous { get; set; }

        /// <summary>
        /// 下一篇
        /// </summary>
        public PostForPagedDto Next { get; set; }
    }
}

同時添加CategoryDtoTagDtoPostForPagedDto

//CategoryDto.cs
namespace Meowv.Blog.Application.Contracts.Blog
{
    public class CategoryDto
    {
        /// <summary>
        /// 分類名稱
        /// </summary>
        public string CategoryName { get; set; }

        /// <summary>
        /// 展示名稱
        /// </summary>
        public string DisplayName { get; set; }
    }
}

//TagDto.cs
namespace Meowv.Blog.Application.Contracts.Blog
{
    public class TagDto
    {
        /// <summary>
        /// 標籤名稱
        /// </summary>
        public string TagName { get; set; }

        /// <summary>
        /// 展示名稱
        /// </summary>
        public string DisplayName { get; set; }
    }
}

//PostForPagedDto.cs
namespace Meowv.Blog.Application.Contracts.Blog
{
    public class PostForPagedDto
    {
        /// <summary>
        /// 標題
        /// </summary>
        public string Title { get; set; }

        /// <summary>
        /// 鏈接
        /// </summary>
        public string Url { get; set; }
    }
}

添加獲取文章詳情接口和緩存的接口。

//IBlogService.Post.cs
public partial interface IBlogService
{
    /// <summary>
    /// 根據URL獲取文章詳情
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    Task<ServiceResult<PostDetailDto>> GetPostDetailAsync(string url);
}
//IBlogCacheService.Post.cs
public partial interface IBlogCacheService
{
    /// <summary>
    /// 根據URL獲取文章詳情
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    Task<ServiceResult<PostDetailDto>> GetPostDetailAsync(string url, Func<Task<ServiceResult<PostDetailDto>>> factory);
}

分別實現這兩個接口。

//BlogCacheService.Post.cs
public partial class BlogCacheService
{
    private const string KEY_GetPostDetail = "Blog:Post:GetPostDetail-{0}";

    /// <summary>
    /// 根據URL獲取文章詳情
    /// </summary>
    /// <param name="url"></param>
    /// <param name="factory"></param>
    /// <returns></returns>
    public async Task<ServiceResult<PostDetailDto>> GetPostDetailAsync(string url, Func<Task<ServiceResult<PostDetailDto>>> factory)
    {
        return await Cache.GetOrAddAsync(KEY_GetPostDetail.FormatWith(url), factory, CacheStrategy.ONE_DAY);
    }
}
//BlogService.Post.cs
/// <summary>
/// 根據URL獲取文章詳情
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public async Task<ServiceResult<PostDetailDto>> GetPostDetailAsync(string url)
{
    return await _blogCacheService.GetPostDetailAsync(url, async () =>
    {
        var result = new ServiceResult<PostDetailDto>();

        var post = await _postRepository.FindAsync(x => x.Url.Equals(url));

        if (null == post)
        {
            result.IsFailed(ResponseText.WHAT_NOT_EXIST.FormatWith("URL", url));
            return result;
        }

        var category = await _categoryRepository.GetAsync(post.CategoryId);

        var tags = from post_tags in await _postTagRepository.GetListAsync()
                   join tag in await _tagRepository.GetListAsync()
                   on post_tags.TagId equals tag.Id
                   where post_tags.PostId.Equals(post.Id)
                   select new TagDto
                   {
                       TagName = tag.TagName,
                       DisplayName = tag.DisplayName
                   };

        var previous = _postRepository.Where(x => x.CreationTime > post.CreationTime).Take(1).FirstOrDefault();
        var next = _postRepository.Where(x => x.CreationTime < post.CreationTime).OrderByDescending(x => x.CreationTime).Take(1).FirstOrDefault();

        var postDetail = new PostDetailDto
        {
            Title = post.Title,
            Author = post.Author,
            Url = post.Url,
            Html = post.Html,
            Markdown = post.Markdown,
            CreationTime = post.CreationTime.TryToDateTime(),
            Category = new CategoryDto
            {
                CategoryName = category.CategoryName,
                DisplayName = category.DisplayName
            },
            Tags = tags,
            Previous = previous == null ? null : new PostForPagedDto
            {
                Title = previous.Title,
                Url = previous.Url
            },
            Next = next == null ? null : new PostForPagedDto
            {
                Title = next.Title,
                Url = next.Url
            }
        };

        result.IsSuccess(postDetail);
        return result;
    });
}

ResponseText.WHAT_NOT_EXIST是定義在MeowvBlogConsts.cs的常量。

TryToDateTime()和列表查詢中的擴展方法一樣,轉換時間為想要的格式。

簡單說一下查詢邏輯,先根據參數url,查詢是否存在數據,如果文章不存在則返回錯誤消息。

然後根據 post.CategoryId 就可以查詢到當前文章的分類名稱。

聯合查詢post_tags和tag兩張表,指定查詢條件post.Id,查詢當前文章的所有標籤。

最後上下篇的邏輯也很簡單,上一篇取大於當前文章發布時間的第一篇,下一篇取時間倒序排序並且小於當前文章發布時間的第一篇文章。

最後將所有查詢到的數據賦值給輸出對象,返回,結束。

BlogController中添加API。

 /// <summary>
 /// 根據URL獲取文章詳情
 /// </summary>
 /// <param name="url"></param>
 /// <returns></returns>
 [HttpGet]
 [Route("post")]
 public async Task<ServiceResult<PostDetailDto>> GetPostDetailAsync(string url)
 {
     return await _blogService.GetPostDetailAsync(url);
 }

編譯運行,然後輸入URL查詢一條文章詳情數據。

成功輸出預期內容,緩存同時也是ok的。

開源地址:https://github.com/Meowv/Blog/tree/blog_tutorial

搭配下方課程學習更佳 ↓ ↓ ↓

http://gk.link/a/10iQ7

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

當全世界的人們隨著網路時代而改變向上時您還停留在『網站美醜不重要』的舊有思維嗎?機會是留給努力改變現況的人們,別再浪費一分一秒可以接觸商機的寶貴時間!

談反應式編程在服務端中的應用,數據庫操作優化,萬條記錄從20秒到0.5秒_網頁設計公司

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

節能減碳愛地球是景泰電動車的理念,是創立景泰電動車行的初衷,滿意態度更是服務客戶的最高品質,我們的成長來自於你的推薦。

反應式編程在客戶端編程當中的應用相當廣泛,而當前在服務端中的應用相對被提及較少。本篇將介紹如何在服務端編程中應用響應時編程來改進數據庫操作的性能。

開篇就是結論

利用 System.Reactive 配合 TaskCompelteSource ,可以將分散的單次數據庫插入請求合併會一個批量插入的請求。在確保正確性的前提下,實現數據庫插入性能的優化。

如果讀者已經了解了如何操作,那麼剩下的內容就不需要再看了。

預設條件

現在,我們假設存在這樣一個 Repository 接口來表示一次數據庫的插入操作。

  csharp

namespace Newbe.RxWorld.DatabaseRepository { public interface IDatabaseRepository { /// <summary> /// Insert one item and return total count of data in database /// </summary> /// <param name="item"></param> /// <returns></returns> Task<int> InsertData(int item); } }

接下來,我們在不改變該接口簽名的前提下,體驗一下不同的實現帶來的性能區別。

基礎版本

首先是基礎版本,採用的是最為常規的單次數據庫INSERT操作來完成數據的插入。本示例採用的是SQLite作為演示數據庫,方便讀者自行實驗。

  csharp

namespace Newbe.RxWorld.DatabaseRepository.Impl { public class NormalDatabaseRepository : IDatabaseRepository { private readonly IDatabase _database; public NormalDatabaseRepository( IDatabase database) { _database = database; } public Task<int> InsertData(int item) { return _database.InsertOne(item); } } }

常規操作。其中_database.InsertOne(item)的具體實現就是調用了一次INSERT

基礎版本在同時插入小於20次時基本上可以較快的完成。但是如果數量級增加,例如需要同時插入一萬條數據庫,將會花費約20秒鐘,存在很大的優化空間。

TaskCompelteSource

TaskCompelteSource 是 TPL 庫中一個可以生成一個可操作 Task 的類型。對於 TaskCompelteSource 不太熟悉的讀者可以通過該實例代碼了解。

此處也簡單解釋一下該對象的作用,以便讀者可以繼續閱讀。

對於熟悉 javascript 的朋友,可以認為 TaskCompelteSource 相當於 Promise 對象。也可以相當於 jQuery 當中的 $.Deferred 。

如果都不了解的朋友,可以聽一下筆者吃麻辣燙時想到的生活化例子。

吃麻辣燙 技術解釋
吃麻辣燙之前,需要先用盤子夾菜。 構造參數
夾好菜之後,拿到結賬處去結賬 調用方法
收銀員結賬完畢之後,會得到一個叫餐牌,會響鈴的那種 得到一個 Task 返回值
拿着菜牌找了一個位子坐下,玩手機等餐 正在 await 這個 Task ,CPU轉而處理其他事情
餐牌響了,去取餐,吃起來 Task 完成,await 節數,繼續執行下一行代碼

那麼 TaskCompelteSource 在哪兒呢?

首先,根據上面的例子,在餐牌響的時候,我們才會去取餐。那麼餐牌什麼時候才會響呢?當然是服務員手動按了一個在櫃檯的手動開關才觸發了這個響鈴。

那麼,櫃檯的這個開關,可以被技術解釋為 TaskCompelteSource 。

餐台開關可以控制餐牌的響鈴。同樣, TaskCompelteSource 就是一種可以控制 Task 的狀態的對象。

解決思路

有了前面對 TaskCompelteSource 的了解,那麼接下來就可以解決文章開頭的問題了。思路如下:

當調用 InsertData 時,可以創建一個 TaskCompelteSource 以及 item 的元組。為了方便說明,我們將這個元組命名為BatchItem

將 BatchItem 的 TaskCompelteSource 對應的 Task 返回出去。

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

搬家費用:依消費者運送距離、搬運樓層、有無電梯、步行距離、特殊地形、超重物品等計價因素後,評估每車次單

調用 InsertData 的代碼會 await 返回的 Task,因此只要不操作 TaskCompelteSource ,調用者就一會一直等待。

然後,另外啟動一個線程,定時將 BatchItem 隊列消費掉。

這樣就完成了單次插入變為批量插入的操作。

筆者可能解釋的不太清楚,不過以下所有版本的代碼均基於以上思路。讀者可以結合文字和代碼進行理解。

ConcurrentQueue 版本

基於以上的思路,我們採用 ConcurrentQueue 作為 BatchItem 隊列進行實現,代碼如下(代碼很多,不必糾結,因為下面還有更簡單的):

  csharp

namespace Newbe.RxWorld.DatabaseRepository.Impl { public class ConcurrentQueueDatabaseRepository : IDatabaseRepository { private readonly ITestOutputHelper _testOutputHelper; private readonly IDatabase _database; private readonly ConcurrentQueue<BatchItem> _queue; // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable private readonly Task _batchInsertDataTask; public ConcurrentQueueDatabaseRepository( ITestOutputHelper testOutputHelper, IDatabase database) { _testOutputHelper = testOutputHelper; _database = database; _queue = new ConcurrentQueue<BatchItem>(); // 啟動一個 Task 消費隊列中的 BatchItem _batchInsertDataTask = Task.Factory.StartNew(RunBatchInsert, TaskCreationOptions.LongRunning); _batchInsertDataTask.ConfigureAwait(false); } public Task<int> InsertData(int item) { // 生成 BatchItem ,將對象放入隊列。返回 Task 出去 var taskCompletionSource = new TaskCompletionSource<int>(); _queue.Enqueue(new BatchItem { Item = item, TaskCompletionSource = taskCompletionSource }); return taskCompletionSource.Task; } // 從隊列中不斷獲取 BatchItem ,並且一批一批插入數據庫,更新 TaskCompletionSource 的狀態 private void RunBatchInsert() { foreach (var batchItems in GetBatches()) { try { BatchInsertData(batchItems).Wait(); } catch (Exception e) { _testOutputHelper.WriteLine($"there is an error : {e}"); } } IEnumerable<IList<BatchItem>> GetBatches() { var sleepTime = TimeSpan.FromMilliseconds(50); while (true) { const int maxCount = 100; var oneBatchItems = GetWaitingItems() .Take(maxCount) .ToList(); if (oneBatchItems.Any()) { yield return oneBatchItems; } else { Thread.Sleep(sleepTime); } } IEnumerable<BatchItem> GetWaitingItems() { while (_queue.TryDequeue(out var item)) { yield return item; } } } } private async Task BatchInsertData(IEnumerable<BatchItem> items) { var batchItems = items as BatchItem[] ?? items.ToArray(); try { // 調用數據庫的批量插入操作 var totalCount = await _database.InsertMany(batchItems.Select(x => x.Item)); foreach (var batchItem in batchItems) { batchItem.TaskCompletionSource.SetResult(totalCount); } } catch (Exception e) { foreach (var batchItem in batchItems) { batchItem.TaskCompletionSource.SetException(e); } throw; } } private struct BatchItem { public TaskCompletionSource<int> TaskCompletionSource { get; set; } public int Item { get; set; } } } }

以上代碼中使用了較多的 Local Function 和 IEnumerable 的特性,不了解的讀者可以點擊此處進行了解。

正片開始!

接下來我們使用 System.Reactive 來改造上面較為複雜的 ConcurrentQueue 版本。如下:

  csharp

namespace Newbe.RxWorld.DatabaseRepository.Impl { public class AutoBatchDatabaseRepository : IDatabaseRepository { private readonly ITestOutputHelper _testOutputHelper; private readonly IDatabase _database; private readonly Subject<BatchItem> _subject; public AutoBatchDatabaseRepository( ITestOutputHelper testOutputHelper, IDatabase database) { _testOutputHelper = testOutputHelper; _database = database; _subject = new Subject<BatchItem>(); // 將請求進行分組,每50毫秒一組或者每100個一組 _subject.Buffer(TimeSpan.FromMilliseconds(50), 100) .Where(x => x.Count > 0) // 將每組數據調用批量插入,寫入數據庫 .Select(list => Observable.FromAsync(() => BatchInsertData(list))) .Concat() .Subscribe(); } // 這裏和前面對比沒有變化 public Task<int> InsertData(int item) { var taskCompletionSource = new TaskCompletionSource<int>(); _subject.OnNext(new BatchItem { Item = item, TaskCompletionSource = taskCompletionSource }); return taskCompletionSource.Task; } // 這段和前面也完全一樣,沒有變化 private async Task BatchInsertData(IEnumerable<BatchItem> items) { var batchItems = items as BatchItem[] ?? items.ToArray(); try { var totalCount = await _database.InsertMany(batchItems.Select(x => x.Item)); foreach (var batchItem in batchItems) { batchItem.TaskCompletionSource.SetResult(totalCount); } } catch (Exception e) { foreach (var batchItem in batchItems) { batchItem.TaskCompletionSource.SetException(e); } throw; } } private struct BatchItem { public TaskCompletionSource<int> TaskCompletionSource { get; set; } public int Item { get; set; } } } }

代碼減少了 50 行,主要原因就是使用 System.Reactive 中提供的很強力的 Buffer 方法實現了 ConcurrentQueue 版本中的複雜的邏輯實現。

老師,可以更給力一點嗎?

我們,可以“稍微”優化一下代碼,將 Buffer 以及相關的邏輯獨立於“數據庫插入”這個業務邏輯。那麼我們就會得到一個更加簡單的版本:

  csharp

namespace Newbe.RxWorld.DatabaseRepository.Impl { public class FinalDatabaseRepository : IDatabaseRepository { private readonly IBatchOperator<int, int> _batchOperator; public FinalDatabaseRepository( IDatabase database) { var options = new BatchOperatorOptions<int, int> { BufferTime = TimeSpan.FromMilliseconds(50), BufferCount = 100, DoManyFunc = database.InsertMany, }; _batchOperator = new BatchOperator<int, int>(options); } public Task<int> InsertData(int item) { return _batchOperator.CreateTask(item); } } }

其中 IBatchOperator 等代碼,讀者可以到代碼庫中進行查看,此處就不在陳列了。

性能測試

基本可以測定如下:

在 10 條數據併發操作時,原始版本和批量版本沒有多大區別。甚至批量版本在數量少時會更慢,畢竟其中存在一個最大 50 毫秒的等待時間。

但是,如果需要批量操作併發操作一萬條數據,那麼原始版本可能需要消耗20秒,而批量版本僅僅只需要0.5秒。

所有的示例代碼均可以在代碼庫中找到。如果 Github Clone 存在困難,也可以點擊此處從 Gitee 進行 Clone

最後但是最重要!

最近作者正在構建以反應式Actor模式事件溯源為理論基礎的一套服務端開發框架。希望為開發者提供能夠便於開發出“分佈式”、“可水平擴展”、“可測試性高”的應用系統——Newbe.Claptrap

本篇文章是該框架的一篇技術選文,屬於技術構成的一部分。如果讀者對該內容感興趣,歡迎轉發、評論、收藏文章以及項目。您的支持是促進項目成功的關鍵。

當前項目已經快要發布 0.1 alpha 版本,歡迎參与討論。

GitHub 項目地址:https://github.com/newbe36524/Newbe.Claptrap

Gitee 項目地址:https://gitee.com/yks/Newbe.Claptrap

文章作者: newbe36524
本文章著作權歸作者所有,任何形式的轉載都請註明出處。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

透過選單樣式的調整、圖片的縮放比例、文字的放大及段落的排版對應來給使用者最佳的瀏覽體驗,所以不用擔心有手機版網站兩個後台的問題,而視覺效果也是透過我們前端設計師優秀的空間比例設計,不會因為畫面變大變小而影響到整體視覺的美感。

小米的“鐵蹄”_網頁設計公司

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

以設計的實用美學觀點,規劃出舒適、美觀的視覺畫面,有效提昇使用者的心理期待,營造出輕鬆、愉悅的網站瀏覽體驗。

雷軍說,小米的模式是「互聯網+製造」。

這顯然指的是現在的小米,一個不同於2010年成立之初,為了一塊手機屏幕、一家代工廠商忙得焦頭爛額的小米。

在過往十年裡,小米恰如其時地趕上了智能手機的全生命周期,從開局到全盛、再到如今的幾近飽和,智能手機成就了移動互聯網,也成就了小米。

小米卻不僅僅是一家手機廠商,至少在這位當時已將金山軟件送上港交所、在投行浸潤多年的知名投資人眼裡,小米應該有更大的格局。

“其實很多人不懂小米,”在接受《中國企業家》採訪時,雷軍如是說。

過往幾年,雷軍多次強調“小米從來都不是一家只做硬件的公司”。實際上,小米在成立之初甚至差點兒成了下一個騰訊。

即使在最終選定智能手機賽道后,小米也一再出圈,做生態鏈、做家電、做物聯網、做“地產”……

「互聯網+製造」,也只不過是小米又一次打破常規的瘋狂生長。

差點兒成了下一個騰訊

小米之所以是小米,是因為智能手機。

其實,在小米成立之初,也曾抓到過另一個機遇,IM(即時通訊)。

2010年10月19日,加拿大滑鐵盧大學一個學生團隊研發出了一款軟件,名為Kik Message。

這是一款基於本地通訊錄與聯繫人直接建立聯繫,並在此基礎上實現免費短信聊天的即時通訊工具,發布兩周內,註冊用戶數就超過了100萬。

當時,本來打算做智能手機、對移動互聯網行業高度關注的小米團隊,最先關注到了這款軟件,僅在一個月後(2010年12月10日),第一代米聊誕生。

米聊誕生時,小米還沒有手機,不過這不要緊,因為當時的米聊是直接上線到安卓、iOS兩大應用市場中的,對於當時擁有多位來自谷歌的大神的小米初創團隊來說,干這樣一款手機軟件自然是輕車熟路。

不過,當時小米團隊中鮮有人能夠預見,這將是一門體量不亞於小米規劃中的主業——智能手機的生意。

自米聊發布后,用戶數幾乎每周翻一倍,短短几個月的時間里,用戶數就達到了100萬,這讓雷軍看到了米聊成為下一代即時通訊工具的希望。

不過,雷軍當時有一個擔心,騰訊會不會跟進。

雷軍當年有三種設想,小米官方授權傳記《一往無前》中對此有詳細描述:

如果騰訊用QQ這個產品來迎戰米聊的話,小米尚有一絲機會,因為QQ在手機上的體驗過重,不符合移動互聯網短平快的用戶體驗;

如果騰訊沒有犯任何戰略錯誤,選擇用完全相同的產品形態來迎戰米聊的話,只有在它能給米聊一年搶跑時間的前提下,小米才有50%的勝算;

如果騰訊在一年之內拿出一模一樣的產品,那麼,騰訊的綜合資源是小米的一萬倍,小米將處於完全的弱勢,屆時,騰訊會把全部的工程資源和推廣資源撲上來,小米獲勝的概率將是零。

結果是,騰訊在這一步上沒有犯錯,而且跟進得相當及時,甚至在關鍵時刻集結重兵壓線。

為什麼當時這家已經成立13年的上市公司會這麼在乎這款“小產品”呢?

原因在於,即時通訊是騰訊的“基本盤”,騰訊丟不起。

就在小米開始籌備米聊過程中,偏安一隅的張小龍帶着一個不到10人的小團隊開始在內部研發同樣的產品。經過兩個月的內部研發后,2011年1月21日,微信正式上線。

接下來就是一場用戶搶奪的近身肉搏戰。

在隨後一段時間里,用戶增長為服務器帶來的壓力讓兩家公司壓力山大,紛紛調來核心團隊開始大軍團作戰,最後的戰局如當下所見——QQ、微信成為騰訊生態體系的兩大“基本盤”,用米聊贏得不少關注度的小米最終轉向做智能手機這一“正業”上

試想一下,如果當時騰訊晚些時日入場、或者小米有足夠的彈藥,小米或將不再是現在的小米,很可能已經成了下一個騰訊。

這是小米離成為“互聯網大佬”最近的一次,或許雷軍不會想到,在此之後的幾年裡,他需要無數次向人們解釋:「小米是一家互聯網公司,不是一家只做硬件的公司」。

小米的“鐵人三項”

做即時通訊無果的小米,最終回到了智能手機這條最初規劃的主業上。

作為互聯網圈內知名投資人、目標全球市場的雷軍,對智能手機的商業模式有自己獨特的理解。

他將智能手機商業模式總結為“鐵人三項”——硬件+軟件+互聯網。

用雷軍的話解釋就是,“把軟件、硬件和互聯網融為一體,可以另闢蹊徑、‘降維攻擊’”。

現在回過頭來看,雷軍提出的“鐵人三項”和喬布斯做智能手機的“封閉體系完美論”如出一轍。

不過也正是用這樣的商業模式,雷軍“勸服”了一個初創團隊,最終將小米手機帶進了全球前五。甚至在今年Q3,小米手機全球出貨量首超蘋果,全球市場排名位列第三。

同樣是在做智能手機這幾年裡,在手機廠商同行眼裡,有點另類的小米還做對了另一件事——小米生態鏈。

生態鏈構建的小米疆界

2013年年底,雷軍做出一個決定——用投資的方式孵化智能硬件公司。

雷軍在小米成立之初提出的“鐵人三項”模式不僅適用於智能手機,同樣適用於大部分智能硬件。

這就是有了後來眾人皆知的小米生態鏈。

談到小米生態鏈,就不得不提及另一位小米聯合創始人,劉德。

劉德是工業設計科班出身,開過設計公司、當過大學老師、到過美國頂尖設計名校留學深造。進入小米后,主抓的是小米手機的工業設計,與雷軍不同,在受命搭建小米生態鏈之前,劉德還不曾干過投資這件事。

正式接手搭建小米生態鏈工作后,劉德從內部組建起一支小型投資團隊,和劉德一樣,這個投資團隊成員是由工程師和設計師組成,對於投資這件事兒,都是只聽過、沒幹過。

正是這支毫無經驗的投資團隊,在短短几年時間里,用工程師思維投出了一個小米生態鏈,小米生態鏈也不負眾望地在互聯網世界里,為小米劃出了自己的疆界。

回到最初小米的設想,雷軍最初為這支投資團隊“划的重點”是「手機周邊」。

早年間小米投資或孵化出的做移動電源的紫米、做數據線的碩米、做智能手環的華米、做藍牙耳機的萬魔聲學,都是沿着這一思路。

在開啟生態鏈計劃時,雷軍曾為小米定下“5年內投資100家生態鏈企業”的目標。

100家生態鏈企業自然不會全都是「手機周邊」,「手機周邊」之外,小米生態鏈還有另外兩個圈層——「智能硬件」、「生活耗材」。

與小米生態鏈計劃幾乎同時展開的,還有小米的IoT業務,小米的IoT業務最初源於一個Wi-Fi模組。

2014年年初的一天,小米聯合創始人黃江吉帶着高自光、殷明君,拿着一個Wi-Fi模組找到雷軍說,“我們研發出了一個Wi-Fi小模組,只要把這個小模組放到任何一個硬件里,這個硬件立刻可以被手機控制,從而連接到我們的IoT網絡中。”

現場,他們還通過手機、燈泡為雷軍進行了Demo演示。

在這之後,殷明君的創業團隊被小米收購,小米IoT部門初步形成。

小米當時的IoT業務開展的並不順利,在外部與家電廠商尋求合作屢屢碰壁后,他們最終將Wi-Fi模組首先應用到了小米生態鏈企業智米的空氣凈化器上。

某種意義上來看,小米的IoT和生態鏈天然互補,生態鏈為IoT提供了落地空間,IoT為生態鏈提供了更高的價值和意義。這也成就了後來小米相對封閉的生態。

隨後幾年時間里,小米生態鏈通過“效率”、“成本”兩把尖刀,硬生生在互聯網世界中劃出了一道印記,這道印記被稱為“小米模式”。

在小米生態鏈出現之前,BAT是擺在所有互聯網創業者面前的三座大山,吳曉波在《騰訊傳》中曾這樣寫道:

在風險甚至流傳着這樣的一個說法:

當一位創業者向投資人解說自己的項目的時候,必須要回答一個問題——騰訊會不會做這個項目?或者,如果騰訊進入,你如何保證不被“幹掉”?

雷軍也曾表示,“在我們布局IoT的同時,也是為了繞開BAT三座大山。”

IoT+生態鏈,讓小米繞開了“三座大山”,開闢了一個新戰場。尤其隨着智能家居、產業互聯網等概念在國內興起,在其他互聯網創業者眼中,小米開始成了一座想要“繞開”的山。

近日在科創板上市的平衡車領域的頭部企業九號機器人,也是小米生態鏈早期投資的智能硬件企業之一。早年間,九號機器人創始人高祿峰此前在接受媒體採訪時曾透露:

當時正在思考生態鏈布局的小米已經將我們的競爭對手都看過了,換句話說,如果小米不投我們,投了別人,我們會非常被動,於是我們開始主動接觸小米。

最終小米投資了九號機器人,2015年10月19日,兩家合作的第一款產品「九號平衡車」,售價1999元,再次打破了行業定價規律。

對於將硬件凈利潤不超過5%的寫進招股書的小米,眾口不一。有人認為,小米這是用低價扼殺了國內同行的生存空間、創新空間;也有人認為,這是又一家有野心的中國企業的崛起。

倒是在翻看《小米生態鏈戰地筆記》一書時,雷鋒網在雷軍為這本書寫注寫的序中看到這樣一句話:

小米,就是要做中國製造業的鯰魚。

隨後幾年裡,小米陸續投資或孵化了近300家企業,在互聯網世界里構建起了小米的疆界,小米這條“鯰魚”也悄無聲息地游進了家電領域。

王川和大家電

與其他手機廠商同行不同,小米一直都是一家不安分的手機廠商。

在建立小米生態鏈之前,小米已經親自下場做了路由器、智能電視。其中,小米電視的靈魂人物是小米第八位聯合創始人,王川。

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網站的第一印象網頁設計,決定了客戶是否繼續瀏覽的意願。台北網動廣告製作的RWD網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上它。

說起來,王川其實不在小米初創團隊之列,也沒有和雷軍一起喝過那碗小米粥,不過,王川卻是又一位在加入小米之前就已經實現了財富自由的人。

王川同樣是一位“帶資進組”的硬件專家。

2012年,加入小米之前,王川就看到了智能電視這一市場機遇。當時,蘋果、谷歌都已經推出了電視盒子,王川的多看科技也開始着手面向國內市場研發這一款產品。這一產品最終在當年11月面世,被命名為小米盒子,成為王川帶給小米的第一份“禮物”。

小米的智能電視要比小米盒子晚一年,那時的智能電視更多是被稱為互聯網電視。

與眾多互聯網風口一樣,2013年,互聯網電視風口同樣引來了不少虎狼之師。

9月5日,在小米2013年年度發布會上,小米電視正式亮相,售價2999元。

然而,即便在國內,想要做互聯網電視的也不只小米一家。國內主流電視廠商聯合互聯網廠商同期發布的互聯網電視並不少見。

9月3日,愛奇藝、TCL聯合發布“TV+”,經典版TV+定價2999元;

9月10日,阿里、創維聯合發布第一款互聯網電視——搭載阿里TV操作系統及創維天賜系統的創維酷開55K1和42K1;

……

此外,當時還有個風頭無兩的樂視。

樂視在5月發布的超級電視S40直接將售價直接壓到1999元,X60在9月23日宣布與騰訊達成深度合作,由騰訊旗下綜合性電商平台易迅網通過“集采、包銷”方式銷售樂視TV·超級電視X60。

當年,幼年的小米電視並不是一枝獨秀,甚至算不上出彩,也正是這個看似不突出的“幼崽”,自那個風雨飄搖的年代堅持到了現在,並成為今日決定小米江湖地位的一款關鍵產品。

在剛剛過去的2019年,小米電視出貨量破千萬台,樂視卻再也不是那個曾經的樂視。

正是由於在小米電視上的大獲全勝,當小米在2019年大刀闊斧地進入大家電領域時,王川再次披甲上陣。

2019年5月17日,小米進行組織架構調整,宣布成立大家電事業部,任命王川為大家電事業部總裁,負責除電視之外的空調、冰箱、洗衣機等大家電品類的業務開展和團隊管理工作。

在小米官宣進入大家電領域之前,已經早早通過生態鏈摸進了大家電領域:

2017年3月11日,小米生態鏈企業雲米發布了雲米互聯網智能冰箱,隨後,雲米又發布了互聯網洗衣機;

2017年8月10日,做空氣凈化器起家的智米發布了1.5P全直流變頻空調;

……

在2019年4月的小米電視發布會上,雷軍再次提及,“大家電業務是小米AIoT戰略重要組成部分和未來10年持續發展藍圖的核心拼圖之一。”

對於小米做家電,雷鋒網接觸的不少行業人士都表示,對於要做智能家居產業鏈的小米而言,做家電也在意料之中。

互聯網廠商做大家電、做白電會有什麼門檻嗎?

雷鋒網向家電行業資深專家了解到:

智能家電其實是家電行業和互聯網行業的一個交集,這個領域就技術難度、市場推廣等方面來說,互聯網企業比傳統白電企業更有優勢。

在具體的生產製造方面,互聯網企業完全可以找OEM代工解決;從產品設計方面來看,他們與有着二三十年行業沉澱的家電行業頭部企業還是有一定差距,現在主要蠶食的其實是中小型家電企業的市場份額。

小米的大家電事業部成立后,不到一年時間里,通過「小米」、「米家」兩個品牌布局了“空冰洗、廚衛電”在內的幾乎所有家電產品,甚至在年底還發布了小米互聯網空調,着實還是為董小姐捏了一把汗。

2013年,在央視年度經濟人物頒獎典禮上,雷軍與董明珠定下“10億賭約”時,曾有一次戲劇性的對話:

董明珠:如果全世界的工廠都關掉了,你還有銷售(額)嗎?

雷軍:我覺得董總是在挑撥離間,小米用的是最好的工廠和最好的供應鏈……

董明珠:(如果)我(的工廠)不給你做呢?

雷軍:今天強調的是專業化分工,做工廠的把工廠做好,做產品的專心做產品……

董明珠:那我空調給你賣算了。

雷軍:可以考慮呀~

董小姐有所不知的是,雷軍當時說的可以考慮的不僅僅是“小米賣空調”,還有“小米開工廠”。

從“敬畏製造業”到“+製造”

在事後回憶起這次很大程度上節目組安排的“對賭”時,雷軍坦言:(當時)確實有點膨脹了。

“膨脹”是因為小米創立前三年吃到了功能機轉智能機的紅利,一直處於“瘋長模式”,手機銷量和公司估值像是吹氣球一樣在快速飆升。到2014年,小米手機已經以12.5%的市佔率位居國內第一(全球第三)。

2014年年底,小米完成又一輪11億美元融資后,估值高達450億美元,5年翻了180倍。

承認“膨脹了”是因為在三年瘋長后,小米開始遭遇增長瓶頸,增速放緩,甚至開始受到質疑。

美國《華爾街日報》援引知情人士消息稱,小米2015年未能達到8000萬部智能手機的銷售預期,投資者也開始質疑該公司高達450億美元的估值。

在隨後接受媒體採訪時,雷軍也透露,小米從2016年提出“要敬畏製造業”,並開始大規模補課硬件、下決心植根製造業。

經過三年補課,小米智能工廠最終出現在雷軍今年的十周年公開演講中。

雷軍說,為了做這間工廠,小米在過去三年時間里投資了110家做智能裝備的公司。

在年底的MIDC 2020上,小米智能工廠的部分細節逐漸對外公布:

除了貼片機,其它絕大部分生產設備採用的都是小米自研的設備。

一期工廠中除了上下料外,實現了全部智能化,一期自動化率達到63%,年底對整機組裝和包裝環節優化后,自動化率提升至75%。

同樣是在年底大會上,小米智能工廠的三年規劃和整體規劃圖也被和盤托出:

2019年,進行自動化建設,通過機器人與自動化建設替代人工;

2020年,進行網絡化建設,通過全面網絡化進行數據採集和應用;

2021年,進行智能化建設,實現基於數據和知識的智能決策。

從做手機跨到做智能工廠,跨度究竟有多大?

雷鋒網向智能製造相關從業人士了解到:

自動化只是智能工廠的初級階段,目前自動化產線相關技術也已經比較成熟,只要找到合適的人,有足夠的經費投入,已經算不上什麼門檻。

推進智能工廠,並不能降低小米手機的成本。手機是一個迭代非常快的產業,生產手機外殼或相關零配件的專用機床,往往三個月到半年就要更新換代,這方面生產設備的成本非常高。即便是智能工廠,成本也不低,所以小米的智能工廠,目前更多應該是應用在市場周期更長的高端手機,例如小米10至尊版。

小米智能工廠的想象空間是基於小米對於用戶需求的收集反饋,打通消費者需求、研發和製造的閉環,類似阿里的犀牛智造。

雷軍是在不惑之年創立的小米,他曾說,改變製造業是小米的終極夢想。

現在,10歲的小米正在用互聯網改變製造業,也在用製造業改變小米。

小米的“鐵蹄”,沒有邊界

如果在小米公司內部孵化硬件企業,必然會降低公司的專註度,這對公司的發展是致命的。

小米成長初期,雷軍曾這樣考慮。

因此也就有了“不做航母,做艦隊”一說,有了小米生態鏈。

不過,在小米成立十年之際再回頭看,你會發現,通過投資、孵化,在手機之外,小米前沖后撞,給自己開闢出一個廣闊的疆域。

我們可以看到,小米除去有手機、音箱等智能硬件外,同時:

在家電行業,就“功能機”轉“智能機”之際,抓住機會,跨界爭奪紅利期;

在製造行業,憑藉自身供應鏈優勢、互聯網基因,借政策東風,加碼加力;

甚至在地產行業,在智能家居、智慧社區中,也可見「小米+生態鏈+金山雲」組合的身影。

小米曾經官宣,在物聯網周期內,小米有「1+4+X」的戰略布局。

而其實,真正的小米,似乎沒有邊界。

就像曾經的一代天驕成吉思汗,“鐵蹄”所到之處,即為帝國疆域。

【本文作者王金旺,由合作夥伴微信公眾號:雷鋒網授權發布,文章版權歸原作者及原出處所有,轉載請聯繫原出處。文章系作者個人觀點,不代表立場。如內容、圖片有任何版權問題,請聯繫(editor@zero2ipo.com.cn)處理。】

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

台中景泰電動車行只是一個單純的理由,將來台灣的環境,出門可以自由放心的深呼吸,讓空氣回歸自然的乾淨,減少污染,留給我們下一代有好品質無空污的優質環境

自如要求業主合同期降租,否則強制解約,租客也被下“逐客令”_網頁設計公司

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

當全世界的人們隨著網路時代而改變向上時您還停留在『網站美醜不重要』的舊有思維嗎?機會是留給努力改變現況的人們,別再浪費一分一秒可以接觸商機的寶貴時間!

近日蛋殼事件持續發酵,不少租客被驅逐、無處可去,房東收不回房租、左右為難,租金貸的弊端盡顯,長租公寓行業存在的問題被充分暴露。

而作為長租公寓行業頭部玩家的自如,被很多打工人看成租房的重要選擇。

但是自如真的靠譜嗎?就在最近,不斷有業主反映自如要求業主合同期內降租,不同意就強制解約,還要賠償違約金。租客也被下逐客令,並且不按合同賠償。

總結一下,自如先是以疫情影響等原因要求業主合同期內降租,否則就單方面解約,而且還算業主違約,須支付違約金,比如裝修費用等。租客則不得不搬離,也不能獲得合同規定的賠償。

有業主更是直言“要麼降租,要麼陪他們裝修費用,呵呵,我們就是任人宰割的小羊,賺了錢是他們的,賠了錢是我們的”。

三言財經了解到,有業主表示從今年6月份自如就打電話談降租,理由是疫情影響,至今中間談了幾次降租的事,但是業主始終沒有同意。

就在最近該業主突然在APP上發現雙方合同正處於解約中。自如在合同期內強行降租,不同意就強制解約。此外,該業主稱,自如強行解約還會算成業主違約,業主還要賠償裝修費。

對於下一步的維權,該業主表示如果12月的房租超過15天沒有支付,會起訴自如。他還稱,自己所在的維權群里已近500人,群里有大量起訴自如的業主。

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

透過資料庫的網站架設建置,建立公司的形象或購物系統,並提供最人性化的使用介面,讓使用者能即時接收到相關的資訊

事實上在微博上,#自如要求業主合同期內降租#的話題已經有近千萬的閱讀量,而相關的爆料最早從今年6月份就已經出現。

隨着最近蛋殼事件的引爆,自如的業主和租客也感受到了緊張,相關爆料也開始多起來。

自如的做法,實際將業主和租客也放到了對立面,三方的矛盾變得無法調和。

對於業主和租客,都面臨兩方的壓力。自如這招算是轉嫁了降低成本所引發的矛盾爆發點。

不僅對業主,自如是兩頭解約,還將問題轉嫁到業主身上。

有租客表示,在強制業主解約后,自如對合約期內的租客下達逐客令。

該租客表示,從業主口中得知,自如拖欠業主兩個月房租,導致業主不得不解約,收回房屋,並沒有收到違約金。但自如卻表述是業主主動解約,還稱業主拒付違約金。

有業主提供的維權群里,維權人員自發的製作了降租解約的應對策略。其中細節及其詳盡,這隻能說維權並不是一件容易的事。

最後對於維權,筆者還是建議受害者們要及時保存證據,在法律範圍內合法維權,多嘗試各種途徑。

【本文作者三言財經,由合作夥伴三言財經授權發布,文章版權歸原作者及原出處所有,轉載請聯繫原出處。文章系作者個人觀點,不代表立場。如內容、圖片有任何版權問題,請聯繫(editor@zero2ipo.com.cn)處理。】

※想知道最厲害的網頁設計公司嚨底家"!

RWD(響應式網頁設計)是透過瀏覽器的解析度來判斷要給使用者看到的樣貌

翻拍《三體》《水滸傳》,Netflix太想講“中國故事”_網頁設計公司

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

透過選單樣式的調整、圖片的縮放比例、文字的放大及段落的排版對應來給使用者最佳的瀏覽體驗,所以不用擔心有手機版網站兩個後台的問題,而視覺效果也是透過我們前端設計師優秀的空間比例設計,不會因為畫面變大變小而影響到整體視覺的美感。

當國內市場熱衷於開發西遊、封神IP時,大洋彼岸的Netflix突然官宣要翻拍被我們忽視了一段時間的經典IP《水滸傳》。

而就在不久前,Netflix才剛剛宣布了攜手游族和劉慈欣,接盤我們的難產科幻大IP《三體》。

Netflix一下釋放兩個“重磅炸彈”,立刻在國內外社交網絡上炸開了鍋。國內觀眾擔心它是第二個《花木蘭》,國外觀眾則純屬隔岸觀火。

兩年前,雄心勃勃征戰亞洲市場的Netflix創始人里德·哈斯廷斯(Reed Hastings)被問及入華計劃時說,Netflix當下的第一要務是講好韓國故事、印度故事、日本故事,而不是中國故事。

那現在,Netflix大張旗鼓開始講起了中國故事,看來是“時機已經成熟”?

Netflix七年入華之路折戟多次,而我們也喊了很久的“狼來了”,這一次真的會來嗎?

台灣日本成入華跳板?

2018年,哈斯廷斯(Hastings)曾說,國內“優愛騰”三個大傢伙太強大了,Netflix不着急進入中國市場。

結果話剛一撂下,轉頭就揮師台灣,斥重金挖來了HBO在台灣的班底,一口氣宣了5部自製原創華語劇。

雖說Netflix華語劇針對的是它開放服務的華語區受眾,但總讓人感覺醉翁之意不在酒,引發了隔岸看戲的我們一陣騷動,Netflix拍華語劇的一舉一動都在被國內渲染報道。

如今兩年過去,Netflix和在內地繞開的“大傢伙”——愛奇藝,在台灣市場卻較量上了。

原本在Netflix出現以前,愛奇藝在台灣流媒體市場擁有一騎絕塵的佔有率。然而現在,據台媒抽樣調查511位觀眾中,雖然Netflix的使用普及率不如愛奇藝,但付費率竟然超過愛奇藝。

可以說,Netflix在台灣首戰告捷,至少有了挑戰愛奇藝的資格。

台灣市場像是Netflix的一塊試驗田,通過台制華語劇摸清大華語區觀眾的喜好,這其中就包含內地觀眾的口味。

不在內地播不代表我們看不了,Netflix上線劇集、電影歷來是內地盜版資源泛濫的重災區。而佯裝對內地市場半放棄的Netflix,實際上時刻偵察着內地市場輿情。

Netflix首部重磅華語劇《罪夢者》邀來的主演賈靜雯、張孝全、范曉萱等,在兩岸都具有很高知名度,自然吸引了內地觀眾的目光。五部劇播下來,基本可以把兩岸觀眾的審美探出一二。令台灣觀眾失望的《罪夢者》,在內地的口碑也崩了。

接檔的驚悚劇《彼岸之嫁》與偶像劇《極道千金》劇情落入窠臼、口碑節節敗退,豆瓣評分4、5分,兩岸口碑一致崩盤。

有趣的是,Netflix第四部推出的是內地不可說的外交題材劇,口碑並沒有出圈。直到第五部懸疑劇《誰是被害者》才終於口碑逆襲,豆瓣評分8.0。

於是,我們看到了不光是台灣媒體鼓吹,內地也鋪天蓋地報道了Netflix華語翻身之作。

看得出來,Netflix也很重視《誰是被害者》在內地的公關。這部劇是唯一被續訂第二季的華語劇,也是Netflix唯一被內地買下的版權劇,合作方不是老熟人愛奇藝,而是新朋友西瓜視頻。

台制華語劇儼然成了Netflix進入內地市場的新名片。而在《水滸傳》項目中,我們看到Netflix找了日本導演佐藤信介執導。

如今中日影視交流頻繁,不知道日制華語劇是不是也將成為Netflix入華的另一張名片。Netflix似乎有意通過兩個地區作跳板,撬開內地大門。

有趣的是,上世紀70年代,西方世界兩次翻拍《水滸傳》《西遊記》都是由日本人完成的。

英國廣播公司(BBC)甚至找了既不懂日語、也不懂中文的人配成英語。一群日本演員配着英語演中國的《水滸傳》,畫面不敢想象。

為什麼不能找中國人拍?

圈內人心知肚明Netflix這些年一直在接觸中國創作者,目前看來是都沒成。

根據一位創作者說法,不接Netflix活兒的最主要原因是不敢。目前國內的監管政策越來越趨緊,勢必會受到影響。

回顧Netflix折戟的入華之路,Netflix似乎就沒弄懂過中國。

七年間,Netflix“緋聞”合作夥伴不斷,幾乎把中國巨頭傳了個遍,樂視、阿里、萬達、保利等等。

這期間,Netflix入華的態度與方式也千變萬化。一會兒自信滿滿單刀赴會,一會兒說要中國小夥伴幫助。

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

節能減碳愛地球是景泰電動車的理念,是創立景泰電動車行的初衷,滿意態度更是服務客戶的最高品質,我們的成長來自於你的推薦。

2015年是Netflix緋聞最多的一年。

年初的時候,哈斯廷斯(Hastings)放言入華不需要合作夥伴,當時連外媒都質疑Netflix不明白前輩Twitter、YouTube等前車之鑒,中國政策不允許境外公司展開視聽服務。

到5月份,Netflix又認慫說不想在沒有合作夥伴的情況下貿然進入,因為入華手續太麻煩了。

根據《好萊塢報道》,Netflix接觸了因《小時代》系列正當紅的樂視,以及華數傳媒、保利、百視通,甚至還給央視旗下的中國網絡電視台拋去了橄欖枝。

及至年末,Netflix還搭上當時正在全世界“買買買”的王健林,剛收購完傳奇的萬達,又被傳出要收購Netflix。可奔波一圈下來,沒一個有下文。

2016年初,哈斯廷斯(Hastings)再次宣稱要獨自入華,Netflix重拾入華手續、努力獲取牌照,儘管可能要花上好幾年的時間。但接着就傳出阿里收購Netflix的消息,尤其在阿里私有化優酷后,傳聞愈演愈烈。

就在這時,Netflix卻突然與愛奇藝達成內容授權合作。2017年5月,Netflix終於邁出了入華實質性的一步。

可這段備受矚目的跨國合作進行得卻異常低調,以致於如果龔宇不講,我們都不知道他們分手了。

2019年5月龔宇稱,“受到審查系統和用戶品味的影響,效果不是太好,所以我們不再繼續合作。”總有種說不明道不清的彆扭。

與愛奇藝結束合作后,一度傳出Netflix要投入優酷懷抱。外媒分析師保羅·佩斯卡托雷(Paolo Pescatore)認為,介於合作過愛奇藝的關係,中國其他巨頭可能已經關上Netflix入華的大門。

他還認為,Netflix目前的中國策略是挖掘全球華人創作者,委託其進行中國內容製作,從而解決Netflix原創內容入華的審查問題。

於是,我們看到了Netflix第一个中國內地合作項目:《飛奔去月球》。

該項目的美國牽頭方為華裔製片人楊燕子,是第五代導演陳凱歌、張藝謀片子在北美引進發行的重要推手。而她在中國的合作方是肩負中國文化走出去使命的東方夢工廠。

與斯皮爾伯格的夢工場分手后,華人文化、上海文廣集團SMG的東方夢工廠失去了大熱IP《功夫熊貓》。另起爐灶的《飛奔去月球》講述中國探月計劃成功與嫦娥故事傳說。但該項目一直延期擱置,直到Netflix接盤。

這種合作模式,或許也會成為Netflix入華的另一種方式。但前提是,得講正能量的中國故事。

Netflix進攻中國動作不斷

此前眾所周知,Netflix入華第一大難題,是辦證困難。但2019年8月19日之後,就不存在這個問題了。

北京市發布《北京市服務業開放改革三年行動計劃》,放寬互聯網遊戲、視頻和圖書等業務的外資准入條件,允許外資在滿足內容監管和數據安全的前提下,提供網絡遊戲下載和網絡視聽節目服務。這意味着,過去阻擋YouTube、Apple TV+進入的政策大門已經打開。

硬糖君注意到,近一年Netflix加大了國產電影、劇集的版權購買,2019年一年的購買量與2018-2017年兩年的量差不多。

Netflix拿下了《流浪地球》《哪吒》《紅海行動》等中國爆款電影版權;買入了涵蓋優愛騰三家的版權劇,比如熱門古裝IP《陳情令》《三生三世十里桃花》《天盛長歌》等,一個都不落下;甚至連甜寵劇、沙雕劇都不放過,買入了《致我們單純的小美好》《致我們暖暖的小時光》《從前有座靈劍山》等。

今年初,其還和於正的歡娛影視試水了首部Netflix獨播的內地劇《金枝玉恭弘=叶 恭弘》。之後還迅速買入了熱播電視劇《下一站幸福》《三十而已》,以及“豪華巨制”的網大《征途》。

從沒見過任何一個國外流媒體如此大手筆的購買國產劇。亞馬遜斷斷續續買過一些國產電影、劇集,一年最多兩部。比如去年買入《少年的你》,與Netflix聯播《初戀這件小事》;2018年和hulu聯播《如懿傳》。

HBO則是除了台劇《我們與惡的距離》,沒有買入過華語劇。

Netflix此番壕買,不單單是為了所服務的華語受眾,應該也是向中國市場示好的一種表現。嘴上說不着急進入中國市場的Netflix,實際上比誰都着急。

Netflix對國際市場的開墾已接近飽和,全球僅剩中國、克里米亞、朝鮮與敘利亞四塊土地尚未涉足。而中國是唯一真正具備巨大消費潛力的國家。

大洋彼岸的股東們時刻關注着Netflix入華的情報,中國故事似乎成了Netflix在股市唯一可講的故事。

而這一時期的優愛騰,也比此前都需要Netflix。

根據QuestMobile報告显示,截止2020年6月,在線視頻行業月活人數相比去年同期下降11%,從9.64億減少到8.57億。與之相反的是短視頻增長勢頭正猛,2018年至2020年,兩年間趕上了在線視頻3億月活的差距。

很明顯,目前國內流媒體市場不僅趨近飽和,還將進入與短視頻“搶”存量用戶的博弈階段。國內開墾飽和的優愛騰與國外開墾飽和的Netflix,正需要彼此的手中王牌,來實現打開新的市場可能。

但Netflix與愛奇藝看來並不愉快的合作、多年入華路與長視頻各家大概也都有過無果的磋商,使其最終繞開了中國同行們。

如前文所述,Netflix最新華語劇《誰是被害者》竟是與長視頻的對頭西瓜視頻合作的。正為美國上市奔波的字節,會為Netflix打開入華的通途嗎?

【本文作者魏妮卡,由合作夥伴微信公眾號:娛樂硬糖授權發布,文章版權歸原作者及原出處所有,轉載請聯繫原出處。文章系作者個人觀點,不代表立場。如內容、圖片有任何版權問題,請聯繫(editor@zero2ipo.com.cn)處理。】

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

搬家費用:依消費者運送距離、搬運樓層、有無電梯、步行距離、特殊地形、超重物品等計價因素後,評估每車次單