知名虐機頻道評選 2020 年智慧型手機耐用獎,誰是最堅固的贏家?_貨運

※智慧手機時代的來臨,RWD網頁設計為架站首選

網動結合了許多網際網路業界的菁英共同研發簡單易操作的架站工具,及時性的更新,為客戶創造出更多的網路商機。

虐機,大概是所有消費者最感興趣的話題,哪一款手機最耐用、哪一款手機耐用性最差,還有更深奧的那些手機最容易被修復等。知名虐機頻道 JerryRigEverything 更是相當有名的其中翹楚,只要提到虐機就絕對不能沒有看過這頻道,近日該頻道評選出 2020 年的各種智慧型手機耐用性獎項,分享給大家一看。

知名虐機頻道評選 2020 年智慧型手機耐用獎,誰是最堅固的贏家?

要說專業拆機,大家會想到的 iFixit,如果講到專業虐機,那當然非 JerryRigEverything 莫屬。在2020 年裡面,該頻道虐盡市面上的主流機型,並且在豐富的經驗累積之下評選出 2020 年的各得獎者,接下來就來為大家列出到底有哪些獎項,又有哪些機型獲選為該獎項的得獎者吧!

(點選後面機型可前往查看虐機影片)

可維修性最高:Google Pixel 5
可維修性最低:黑鯊 3
最具創新性機型:ZTE Axon 20
榮譽獎:LG Wing
內部結構最好看的機型:iPhone 12 Pro Max
耐用性最差手機:OnePlus Nord
最讓人迷惑的手機:Google Pixel 5
耐用性最佳手機:Google Pixel 4a

從 2016 年開始,該頻道每年都會將虐過的手機整理起來,在看似無目的的破壞同時了解各手機的耐用度,並且在隔年初進行最終評分,讓大家都能了解過去這一年裡面哪些手機最是頭好壯壯。下面就與大家分享完整版的影片(前半段大概講了投入各種公益,還有自家買了什麼東西…)。

※回頭車貨運收費標準

宇安交通關係企業,自成立迄今,即秉持著「以誠待人」、「以實處事」的企業信念

當然這裡被列入的機型都是比較大眾化、一般消費型手機,所以那些本來就是特定職業人士或專門設計在嚴峻環境中所使用的三防手機自然不在其中。

您也許會喜歡:

【推爆】終身$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元/分

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

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

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

中國媒體實測高通 S888 處理器後,竟用「翻車」形容!功耗高也非常燙_租車

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

日本、大陸,發現這些先進的國家已經早就讓電動車優先上路,而且先進國家空氣品質相當好,電動車節能減碳可以減少空污

對於 Android 用戶來說,今年最期待的旗艦處理器不外乎就是高通 Snapdragon 888,已經發表的小米 11 正是搭載這顆處理器,而最近一間中國媒體「極客灣Geekerwan」就收到小米 11 實機,沒想到測試之後他們卻用 “翻車” 來形容這顆處理器,認為三星的 5nm 工藝讓這顆變得有點慘,功耗實在是太高了。

中國媒體實測高通 S888 處理器

稍早極客灣Geekerwan 於 YouTube 頻道中分享 S888 的評測影片,標題寫著「驍龍888性能分析:翻車!」,看到這翻車形容詞,就知道表現比他們預期的差很多。

影片一開始有詳細講解 S888 的架構,有興趣的人文末有影片,這邊就簡單介紹一下。

S888 跟上一代 S865 相比,GPU 效能提升了 40%:

製程部分受惠於從台積電的 7nm 變成三星 5nm,S888 這次就直接內置 X60 基帶,不像 S865 採用的是外掛 X55 基帶:

進到效能實測部分,Geekbench 5 結果顯示,S888 無論單核心與多核心,確實都比 S865 還要快,提升幅度達 9.7%。跟 A13 相比,多核心終於正式超越,但單核心還是輸,A14 則兩項都輸:

S888 的 LPDDR5 也提升到 6400Mbps,實測記憶體延遲確實比 865 還低,頻寬也提升到 32.5GB/s,整體來看 S888 的效能確實有提升,那為什麼他們會用翻車來形容?主要是在「功耗」:

CPU 能耗比測試結果顯示,888 的功耗 865 高出 1W,達到 3.3W,換算後的能耗比較差:

接著在測試多核心部分,差距又更大了,S888 的功耗來到 7.8W,跟 S865 相比高出近 2W,而且不只是 S888 的 X1 大核心,即使是 A78 中核與 A55 小核的功耗也很高,因此是三星的 5nm 製程工藝導致這個結果:

接著測試光明山脉這款遊戲,像來非常穩定的高通處理器,第一次出現降頻的問題:

比較其他處理器可以發現,最高 FPS 表現雖然可以接近 A13 的水平,但經過 10 分鐘後,就變成跟上一代 S865 一樣:

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

有別於一般網頁架設公司,除了模組化的架站軟體,我們的營業主軸還包含:資料庫程式開發、網站建置、網頁設計、電子商務專案開發、系統整合、APP設計建置、專業網路行銷。

另一款知名原神手遊,沒想到 S888 跑不贏 S865 的小米 10,而且 FPS 波動很大,他們開啟 CPU 核心頻率查看發現,大核 X1 經常保持在 0.8GHz 的低頻上:

跟上一代 S865 相比,大核 A77 可以持續保持 2.84GHz:

檢查 20 分鐘遊玩後的溫度,小米 11 背面接近 48 度:

側面也有 46 度左右,由此可見功耗有多高,遊戲完久真的會很燙手。他們也補充,感覺的出來小米團隊已經盡力壓低小米 11 溫度,依照先前的功耗測試,原本以為會超過 50 度:

如果是玩比較不吃效能的遊戲,S888 功耗確實可以比較低一點,但依舊比 S865、麒麟9000 與 A14 還高,S865 還是採用台積電 7nm 製程:

而再更低要求的遊戲,雖然功耗差距縮小,但會買 S888 手機的人,一定會想玩那些重畫質的遊戲,要不然沒意義:

S888 的實測結果真讓人很意外阿!這功耗也太恐怖,未來有大算入手 S888 手機的人,這點可能要多注意一下。

完整影片:

知名虐機頻道評選 2020 年智慧型手機耐用獎,誰是最堅固的贏家?

您也許會喜歡:

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

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

※超省錢租車方案

商務出差、學生出遊、旅遊渡假、臨時用車!GO 神州租賃有限公司!合法經營、合法連鎖、合法租賃小客車!

小米11 Lite 通過 FCC 認證,相關規格提前曝光!_包裝設計

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

網動廣告出品的網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上她。

小米除了「數字旗艦」之外,近年也會針對年輕族群等相對輕量使用需求推出系列的 Lite 青春版,近期也有款疑似為小米11 系列的新機通過 FCC 認證,也讓部份規格提前曝光。這款傳聞為小米 11 Lite 的新機預計配備 6GB RAM 和 128GB ROM ,內建 4250mAh 大電量電池且支持最高 33W 有線快充。

▲圖片來源:The Pixel(YouTube)

小米11 Lite 通過 FCC 認證,相關規格提前曝光!

雖然,目前還不確定小米11 未來是否有機會、何時才會引進台灣銷售,不過最近傳出小米11 系列除了預期在農曆新年後登場的小米11 Pro 旗艦,還可能會推出一款相較「輕量」的小米11 Lite 。最近隨著 FCC 認證通過的文件曝光,也有更多關於小米11 Lite 的規格傳聞陸續曝光。

▲圖片來源:The Pixel(YouTube)

根據 FCC 等認證的文件可確認,這款型號 M210K9AG 的小米新機全系列皆配備 6GB RAM ,儲存空間分為 64GB 和 128GB 兩種容量選擇。

▲圖片來源:FCC

而小米11 Lite 預計是款 4G 手機,傳聞將搭載 Qualcomm Snapdragon 732G 處理器:

▲圖片來源:FCC

電池容量方面,小米11 Lite 將內建 4250mAh 大電量電池,同時也支持最高 33W 的有線快充:

這項消息也與數碼閒聊站在微博的爆料吻合,而數碼閒聊站也提到小米11 Lite 將從上一代的水滴螢幕升級成單挖孔螢幕:

▲圖片來源:數碼閒聊站(微博)

也有 YouTube 頻道「The Pixel」分享小米11 Lite 的外觀渲染圖,小米11 可能採取單挖孔螢幕將前置鏡頭設計在螢幕左上角,且螢幕可能支持最高 120Hz 更新率:

▲圖片來源:The Pixel(YouTube)

▲圖片來源:The Pixel(YouTube)

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

上新台中搬家公司提供您一套專業有效率且人性化的辦公室搬遷、公司行號搬家及工廠遷廠的搬家服務

雖然關於小米11 Lite 的相機規格目前未有太多的消息,不過傳聞將比照小米11 的設計風格並配備 6400 萬像素的三鏡頭主相機。

▲圖片來源:The Pixel(YouTube)

消息來源:FCC

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

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

您也許會喜歡:

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

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

※產品缺大量曝光嗎?你需要的是一流包裝設計!

窩窩觸角包含自媒體、自有平台及其他國家營銷業務等,多角化經營並具有國際觀的永續理念。

Apple 新專利把 MacBook 變成手機與手錶的無線充電板_台中搬家

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

台中搬家公司推薦超過30年經驗,首選台中大展搬家

對現代人來說,手機沒電這件事情恐怕比筆電沒電還讓人焦慮, 近日國外媒體發現,Apple 剛獲得兩項美國的新專利,把 MacBook 變成能夠時時為行動裝置充電的無線充電板,也就是將反向充電技術移植到筆電上面,不過專利就只是專利,實用性跟技術上的問題當然還是需要多多思考。

Apple 新專利把 MacBook 變成手機與手錶的無線充電板

iPhone 12 系列相較於過去得機型多了便於用再 MagSafe 充電的磁鐵。從 Apple 的專利圖中可以看到,在 MacBook 觸控板以及旁邊左右兩側的手托區域裝置了無線充電線圈,用於在筆電關閉時對其它行動裝置,像是 iPhone、iPad 或是 Apple Watch 充電,而在其中也會加設磁鐵,以便正確地與其他裝置的無線充電線圈對齊。

除了上面提到的方式外,在闔上 MacBook 蓋子時你還可以把 iPad、iPhone 與 Apple Watch 放在蓋子上進行充電。支援反向充電也意味著設備可以用來接收與傳輸電力,就像 Google Pixel 5 一樣,而 Apple 也解釋道,內建的反向無線充電可以解決外出時必須為各種裝置攜帶多個充電器,或是所需用於充電的插座不足的問題,在 COVID-19 疫情結束人們恢復旅行後應可大有助益。

但正如 The Verge 所述,Apple 現行的 MacBook 皆採用鋁合金外殼,自然是無法適用於無線充電所需要的條件(只有玻璃與塑膠可用),以 Google Pixel 5 為例,該手機在鋁合金背蓋上為無線充電線圈挖了一個洞並以生物樹脂或塑膠填補來解決這個問題。另外還要思考的是發熱的問題,一般來說無論是有線或無線充電難免都會有升溫的情況,如何抑制溫度以確保供電與接收電力裝置兩方的運作,都是需要想辦法來克服的。我忽然想到胎死腹中的 AirPower。

台中搬家公司費用怎麼算?

擁有20年純熟搬遷經驗,提供免費估價且流程透明更是5星評價的搬家公司

◎資料來源:The Verge、9to5Google

您也許會喜歡:

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

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

台中搬家公司費用怎麼算?

擁有20年純熟搬遷經驗,提供免費估價且流程透明更是5星評價的搬家公司

蘋果 App Store 突破 2 千億美金收益,Apple Music 與 Apple TV 也創新紀錄_台中搬家公司

※推薦台中搬家公司優質服務,可到府估價

台中搬鋼琴,台中金庫搬運,中部廢棄物處理,南投縣搬家公司,好幫手搬家,西屯區搬家

從全球基本沒人能逃離疫情影響的一年跨入 2021,擁有眾多數位服務的蘋果,也恰好創了不少新里程碑。其中最大的項目,應該是目前蘋果生態系的重要核心,已伴隨開發者與使用者十多年的 App Store 的最新成績單。繼續閱讀蘋果 App Store 突破 2 千億美金收益,Apple Music 與 Apple TV 也創新紀錄報導內文。

▲圖片來源:

蘋果 App Store 突破 2 千億美金收益,Apple Music 與 Apple TV 也創新紀錄

擁有軟硬體數位服務全面掌控的優勢,打造出十分完整生態系的 Apple。選在 App Store 突破 2 千億美金收益的這個時間點,盤點了自家服務行至今日的成績單。

關於應用程式商店的部分,自 2008 年上線時至今已累積了極為可觀的開發者與用戶基礎,再加上近期 Apple 針對小型開發者減半抽成的友善政策,還有疫情導致更多居家時間的關係。App Store 在今年聖誕夜至跨年夜間的這週,據稱使用者就一共消費了 18 億美金的數字 — 甚至元旦當日還以 5.4 億美元消費刷新了紀錄(太威了吧)。

除了 App Store 以外,已經逐漸構築成一圈(?)「Apple One」訂閱服務的這個生態圈。官方也公布了相關的里程碑,包括 Apple Music 新的立即聆聽、全新的搜尋、個人化電台以及自動播放體驗,現在已被超過 90% 的 iOS 14 用戶使用當中;歌詞功能的用戶也增加了兩倍之多。

此外,透過近期開放眾多電視平台使用的策略下,Apple TV app 現在也已經在全球超過 100 國和地區超過 10 億台設備觀看;Apple TV+ 服務 2019 年上線至今也沒多久,不過也獲得超過 149 個獎項提名。喔對了,在台灣也已經非常普遍的 Apple Pay。據稱現在在英美的普及率已經達到 85% 與 90%,甚至在澳洲更是有 99% 的零售商店都支援這樣的支付功能。也是蘋果推行的相當成功的使用體驗之一。

講起來,台灣近年相對以往也變得越來越快就可以獲得蘋果的服務與功能了,不知道大家還有期待哪些服務可以進入台灣呢?交通卡?Apple Card 還是 Fitness+?可以留言跟我們聊聊啊。

本篇圖片 / 引用來源

延伸閱讀:

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

還在煩惱搬家費用要多少哪?台中大展搬家線上試算搬家費用,從此不再擔心「物品怎麼計費」、「多少車才能裝完」

AirPods Pro 推超「牛」限量版,主動式降噪讓你隨時找到專屬自己的空間

傳超值款 iPad(第九代)將更薄更輕且依然有指紋辨識,至於 iPad Pro…

您也許會喜歡:

【推爆】終身$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語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上它。

「MoreThanJava」一文了解二進制和CPU工作原理_如何寫文案

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

擁有後台管理系統的網站,將擁有強大的資料管理與更新功能,幫助您隨時新增網站的內容並節省網站開發的成本。

  • 「MoreThanJava」 宣揚的是 「學習,不止 CODE」,本系列 Java 基礎教程是自己在結合各方面的知識之後,對 Java 基礎的一個總回顧,旨在 「幫助新朋友快速高質量的學習」
  • 當然 不論新老朋友 我相信您都可以 從中獲益。如果覺得 「不錯」 的朋友,歡迎 「關注 + 留言 + 分享」,文末有完整的獲取鏈接,您的支持是我前進的最大的動力!

Part 1. 原來,我們是這樣記數的

本節內容節選自下方 參考資料 1

在討論「二進制」和「CPU 如何工作」之前,我們先來討論一下我們生活中最稀疏平常的 数字,我們與之頻繁地打交道:一個約定的時間、一件商品的價格、一個人的身高….卻很少有人細細想過,這些数字是如何表達出來的?為什麼你理所當然地把 1024 理解為「一千零二十四」而不是別的含義?

也許你從未想過,在這簡單的記數中,沉澱着人類的大智慧。

一進制計數法

  • 圖片來源:https://www.goethe.de/ins/cn/cn/kul/mag/20629923.html

早在数字的概念產生之前,人類就學會了使用樹枝、石子、貝殼等自然界隨處可見的小物件表示獵物的、果實的、部落人口的數量。比如在某個角落堆上一堆石子,每打到 1 只獵物,就扔 1 顆石子進去,每吃掉 2 只獵物,就從中取走 2 顆石子。他們並不在意石子的總數,只是時不時地瞅一眼,心底大致有數。

其實這是一種最樸素的記數方式,數學家稱之為 一進制記數法(unary numeral system)。我們把它符號化一下,比如用斜杠 / 來表示:

  • 1 就是 /
  • 2 就是 //
  • 4 就是 ////

好像沒毛病,我們平時掰手指用的就是這種記數法,但数字一大,場面就要失控了。

符值相加記數法

為了解決記錄大數的問題,於是我們得發明一些其他符號來表示更大的數值,比如用橫杠 - 表示 10,用十字 + 表示 100。那麼:

  • 16 就是 -//////;
  • 32 就是 ---//;
  • 128 就是 +--////////;

漂亮….這種靠符號類型和符號數量表示数字的方法被稱為 符值相加記數法(sign-value notation),古埃及和古羅馬用的都是它,只不過符號各不相同。

古埃及的記數符號:

1 10 100 1000 10000 100000 1000000

1024 在古埃及就寫作:

你會發現,符值相加記數法的一大優點是,符號的順序可以任意打亂,数字含義不受影響。我國藏族曾用石子表示 1、木棍表示 10、果核表示 100、蠶豆表示 1000、瓦片表示 10000,那麼,當你把 1 顆蠶豆、2 根木棍和 4 顆石子胡亂地攥在手裡,別人依然知道它們是 1024

古羅馬的做法略有不同,他們對五進制情有獨鍾:

1 5 10 50 100 500 1000
I V X L C D M

這些符號沿用至今,想必大家(至少對前 3 個)都比較熟悉,許多鐘錶仍保留着使用羅馬数字的習慣,1~12 分別表示為:IIIIIIIVVVIVIIVIIIIXXXIXII。你會發現,羅馬記數法是符值相加記數法的變種,因為它不光「相加」,還「相減」。這種方式就不允許符號亂序了,IVVI 表示的是不同的数字。

那羅馬人何苦要使用這種更複雜的記數法呢?無非是為了讀寫方便。同樣表示 9IXVIIII 更簡潔。

其實有一種更好使的方法——用另外一些列符號來表示符號的數量。比如用 A 表示 1 個符號,用 B 表示 2 個符號,以此類推,用 I 表示 9 個符號。

如此,上文表示 256++-----////// 就可以寫作 B+E-F/。你一定感覺莫名其妙,這種寫法哪裡方便了。其實中文的數字錶示就是這種形式,只不過我們用得太習慣了,以至於沒有發現。

在中文中, 代替了 /-+,而 代替了 ABC256 就寫作 二百五十六個 比較累贅,我們通常把它省略了。

其實像日語、英語用的也同樣是這種記數法,簡潔、優雅。

美中不足的是,這種形式雖便於讀寫,卻不便於計算。中國古人為算籌和算盤這類經典算具搭建起廣闊的舞台,卻沒給筆算留出一席之地。想象一下,如果讓你把這些漢字寫在草稿紙上,列個豎式,你的內心一定非常彆扭。

位值制記數法

公元5世紀,印度數學家阿耶波多(Aryabhata 476–550)創立了現在廣泛使用的 位值制記數法(positional notation/place-value notation),該記數法使用的主要符號,是同為印度人發明的阿拉伯数字:0123456789

與符值相加記數法類比,位值制中的 123 代替的是 ABC,那 /-+ 呢?是 靠阿拉伯数字的位置來表示的。眾所周知,最右位相當於 /,次右位相當於 -靠每個位置上的數值來表示数字,故名位值制。

嚴謹的數學家用一種多項式高度概括了位值制記數法的本質,在十進制中,這個多項式是這樣的:

這是一個 n 位十進制數,ai 就是第 i 位上的數值。為便於直觀理解,舉個 1024 的例子吧:

由於我們熟悉了十進制,這樣費心費力的展開可能會讓你覺得好笑,但當我們把它推廣到其他進制時,這個多項式的價值就體現了出來。n 位 b 進制數的位值製表示:

1024 用二進制怎麼表示?

因此,1024 的二進制寫作 10000000000

除了最普遍的十進制和計算機中的二進制,常見的還有七進制(如 17 天)、十二進制(如 112 個月)、十六進制(如古代 116 兩)、六十進制(如六十甲子)等等,只要有意義,任何進制都可以為你所用。

非標準位值制

在上述的多項式中,如果 ai 或 b 的取值奇葩一點,就形成了 非標準位值制(non-standard positional numeral systems),這類記數法往往應用於專業領域,很難在日常生活中見到。比如標準位值制中的三進制 ai 的取值為 012,但在一種名為平衡三進制(balanced ternary)的非標準位值制中,ai-101,蘇聯曾使用這種進制研發电子計算機。

Part 2. 二進制簡介

  • 圖片來源:https://zhuanlan.zhihu.com/p/26743163

至此,你對「二進制」應該會感覺親切了些,它只是一種數制而已,本質上與我們熟悉的十進制沒有很大的差別,我們這一 Part 來稍微理解一下二進制。(至於電腦為什麼使用二進制我們在下一 Part 中介紹)

二進制的基本運算

十進制中的那些基本運算原則,二進制中同樣適用,只不過需要稍加變幻而已,下面我們分別就加、減、乘、除四則運算來介紹。

二級制加法

根據「逢二進一」規則,二進制數加法的法則為:

0+0=0
0+1=1+0=1
1+1=0 (進位為1) 
1+1+1=1 (進位為1)

例如:11011011 相加過程如下:

二進制數的減法

根據「借一有二」的規則,二進制數減法的法則為:

0-0=0
1-1=0
1-0=1
0-1=1 (借位為1)

例如:1101 減去 1011 的過程如下:

二進制的乘法

二進制數乘法過程可仿照十進制數乘法進行。但由於二進制數只有 01 兩種可能的乘數位,導致二進制乘法更為簡單。二進制數乘法的法則為:

0×0=0
0×1=1×0=0
1×1=1

例如:10011010 相乘的過程如下:

二進制的除法

二進制數除法與十進制數除法很類似。

例如:100110 ÷ 110 的過程如下:

二進製為什麼能表示所有的數據

因為編碼規定。

之前我們有說到,所有保存的程序和數據在計算機中都被描述為 文件,也就是說我們能夠知道當前的數據集合被期望的用途是什麼,也就能夠找到對應的 處理器 來正確處理當前的數據。

例如保存文字

拿文字舉例,為了讓一串 01 能夠代表特定的文字,人們規定使用一個字節中的七位來表達特定的文字, 這就是大名鼎鼎 ASCII (American Standard Code for Information Interchange) 碼,ASCll 碼能夠表達 27=128 種字符(編碼從 0~127),對於 26 個英文字母和一些常用的可打印字符,這完全足夠了:

可是,世界文化是多元的,面對類似漢字這樣的象形文字,ASCll碼錶用起來自然是捉襟見肘。

窮則思變,一個字節不行,那就兩個字節,這就是大名鼎鼎的 Unicode 碼,不難看出,Unicode 碼有 216=65536 種表示方式,這樣就足以表達一些常用的字符了,值得一提的是,Unicode 碼算是在 ASCll 碼上的一種擴充,其第 0~127 個編碼字符與 ASCll 碼錶一模一樣。

再比如圖片

這裏涉及一點點物理知識,話說很久以前,牛頓通過三稜鏡把白色的光分解成七種不同顏色的光,後來又通過各種實驗發現紅、綠、藍三種顏色的光是無法被分解的,因此我們就稱為紅藍綠為光的三原色。

至此人類已經知道了:可以通過組合不同比例的紅、綠、藍三種顏色來獲得各種各樣的顏色,那麼我們就可以在計算機上模擬了。現在的計算機,一般使用 32 位來表示顏色,32 位平分給四個分量,也就是每個分量 8 位。

為啥是四個顏色分量?

因為顏色模型中有一個 alpha 值,用來表示透明度,這一點我們先不考慮。總之三種顏色,每個使用 8 位來表示的話,我們就能夠表示 256 * 256 * 256 = 16777216 種顏色了,已經足夠基礎的使用了。

先來看一張圖片:

這張圖像的尺寸是 600px * 664px(px 是一種圖片單位,中文名稱為像素,你可以暫時理解為一個點)。我們把它放大一下,如下圖所示:

※教你寫出一流的銷售文案?

銷售文案是什麼?A文案是廣告用的文字。舉凡任何宣傳、行銷、販賣商品時所用到的文字都是文案。在網路時代,文案成為行銷中最重要的宣傳方式,好的文案可節省大量宣傳資源,達成行銷目的。

看見了嗎?實際上,大部分圖像(你拍攝的照片、你掃描的圖片、你使用 iPad 畫的圖片等等…)都是位圖文件,位圖就是由像素點構成的,它就像是一個網格一樣,每個格子裏面填一個顏色。(除了位圖外,還有一種圖是矢量圖,它描述的是形狀而非網格)

OK,我想你已經能理解圖像是由像素點組成的了(事實上我們的显示器也是),我們只需要在編碼中附帶上一些額外的信息,例如圖像有多大的尺寸、時間、作者、顏色深度、是否支持透明度之類的就能夠對圖像進行正確表示了。(視頻可以簡單理解成一張張連續不斷的圖片)

要讓显示器正確显示圖片或者視頻,只需要讓显示器上每個像素显示特定的顏色就好了。

  • 圖片來源:https://www.bbc.co.uk/bitesize/topics/zf2f9j6/articles/z2tgr82

Part 3. 為什麼是二進制?

  • 圖片來源:https://zhuanlan.zhihu.com/p/33439000

可為什麼一定是二進制呢?使用人類習慣的十進制不好嗎?

理由一:物理上易於實現

計算機依靠電力工作,這也就意味着需要將数字信號映射到電信號,實現這種映射最簡單的方法是:

  • 0 – 沒有電(0 V)
  • 1 – 有點(5 V)

二進制在技術上最容易實現。這是因為具有兩種 穩定狀態 的物理器件很多,如門電路的導通與截止、電壓的高與低等,而它們恰好可以對應表示 “1” 和 “0” 這兩個數碼。假如採用十進制,那麼就要製造具有 10穩定狀態 的物理電路,而這是非常困難的。

理由二:機器可靠性高

為什麼使用更複雜的数字系統是一個問題?

假設我們使用三元(3 位数字)数字系統涉及計算機,如果我們具有從 0 V5 V 的電壓,那麼我們可以進行以下的映射:

  • 0 – 0 V;
  • 1 – 2.5 V;
  • 2 – 5 V;
  • 圖片來源:https://pmihaylov.com/intro-binary-numbers/

看起來合理吧?但是,想象一下,我以 2.5 V 的電壓發送了一個数字。但是由於電路中的一些噪聲,我在輸出端得到 2.3 V 的電壓,因此將其視為 0。結果是?

有人給我發送了 1,但我將其視為 0。數據丟失可是一個非常嚴重的問題。

使用二進制則可靠得多,由於電壓的高和低、電流的有和無等都是一種 質的變化,兩種物理狀態穩定、分明,因此,二進制碼傳輸的抗干擾能力強,鑒別信息的可靠性高。

為什麼計算機系統必須有時鐘

  • 圖片來源:http://programmedlessons.org/Java9/chap02/ch02_11.html

建立数字系統的目的是 僅在某些時間點測試開/關(二進制)值,這使電線(或其他設備)有時間更換。這就是計算機系統有時鐘的原因。

時鐘會周期性地進行信號的測量,圖中所示的 T1 和 T2 就是可以測量信號的時間點。

時鐘利用所有這些時間點來保持同步。更快的時鐘意味着每秒可以對電線進行更多次測試,並且整個系統運行得更快。2 GHz 處理器每秒檢查二進制值 20 億次。在這些時間之間,允許值改變並穩定下來。處理器芯片速度越快,每秒可以測試的次數就越多,每秒可以做出的決策就越多。

理由三:運算規則簡單

數學推導已經證明,對 N 進制數進行算術求和或求積運算,其運算規則各有 N(N+1)/2 種。如採用十進制,則 N=10,就有 55 種求和或求積的運算規則;而採用二進制,則 N=2,僅有 3 種求和或求積的運算規則,以上面提到的加法為例:

0+0=0,0+1=1 (1+0=1),1+1=10

因而可以大大簡化運算器等物理器件的設計。

理由四:邏輯判斷方便

採用二進制后,僅有的兩個符號 “1” 和 “0” 正好可以與邏輯命題的兩個值 “真” 和 “假” 相對應,能夠方便地使用邏輯代數這一有力工具來分析和設計計算機的邏輯電路。

雖然在 1950 年代就造出了更加高效的三元計算機,但在效率和複雜度的取捨上,始終抵不過二進制。二進制仍然在當今世界中長期存在。

Part 4. CPU 的實際工作方式

上面我們了解到計算機以二進制的形式運行,它們只有兩種狀態:開(1)和關(0),為了執行二進制計算,我們需要採用一種特殊的电子元器件,稱為 「晶體管」。暫時我們把它理解為一種開關吧,通電就打開,沒電流通過就關閉。

利用”開關”搭建邏輯電路

我們知道,給電燈通上電,它就會亮:

於是,結合上開關,我們就能搭建出最基礎的 與門或門

與門

該電路的邏輯是:只有當 A 和 B 同時開啟時,LED 燈才會亮,也就是認為輸出 1,我們可以利用電信號來簡單模擬一下:

A B Y
0 0 0
1 0 0
0 1 0
1 1 1

或門

該電路的邏輯是:當 A 或者 B 開啟時,LED 燈就會亮,也就是認為輸出 1,我們可以利用電信號來簡單模擬一下:

A B Y
0 0 0
1 0 1
0 1 1
1 1 1

其他門

類似地,我們可以藉助更多的电子元器件來創造出基礎的 7 種邏輯門電路:

  • 圖片來源:https://www.zhihu.com/question/348237008/answer/843382847 | @Zign

這裏需要特別提一下 異或門,我們需要先知道有一種电子元器件可以利用電氣特性對 輸入取反,也就是說輸入 1 則輸出 0,輸入 0 則輸出 1,那麼我們就可以 簡單模擬 出異或門邏輯電路(實際會更複雜些,這裏僅展示出異或的意思):

A'B' 分別表示 AB 開關的反值,從圖中我們很容易知道只有當 AB 只存在一個輸入 1 時,整個電路才會輸出 1

利用邏輯門簡單計算加法

OK,上面我們了解到我們能夠利用 “開關” 來模擬邏輯的運算,我們接下來試着還原一個簡單的加法運算器是如何實現的:

僅需兩個門,就可以完成基本的二進制加法運算。上圖是利用 logic.ly 創建的半加法器,AB 相當於使我們計算的兩個數,最後一塊相當於是我們的數顯芯片,它的功能是根據輸入显示数字,從上到下的引腳(也就是圖中輸入的地方,通常我們這樣稱呼)分別對應了 20=121=222=423=8 的輸入,沒有任何輸入時显示為 0,如果 引腳 1(對應 20=1)像上圖一樣有輸入,則显示 0 + 1 = 1

我們來理解一下上方的電路:

  • 如果僅打開一個輸入,但不同時打開兩個輸入,則此處的 XOR 門(異或門)將打開,此時對應輸入 引腳 1,显示 数字 1(類似於 1 + 0 和 0 + 1);
  • 如果兩個輸入均打開,則 AND 門(與門)將打開,此時對應輸入 引腳 2,显示 数字 2(類似於 1 + 1);
  • 如果沒有輸入,則 AND 門和 XOR 門都保持關閉,此時显示 数字 0(類似於 0 + 0);

因此,如果兩個都打開,則 XOR 保持關閉,並且 AND 門打開,得出正確的答案為 2

但這隻是最基礎的半加法運算器,不是太有用,因為它只能解決最簡單的數學問題之一。但如果我們把它們兩個與另一個輸入連接,就會得到一個完整的加法器:

仔細思考幾遍,你就會得知這個三個輸入的加法器已經可以計算 3 個二進制数字的加法運算了,我們如法炮製,可以通過連接更多的”進位”來使這個加法器能夠運算更多的數,這當然也意味着這個計算鏈條更長。

大多數其他數學運算都可以加法完成。乘法只是重複加法,減法可以通過一些奇特的位反轉來完成,而除法只是重複減法。並且,儘管所有現代計算機都具有基於硬件的解決方案以加快更複雜的操作,但從技術上講,您可以使用完整的加法器來完成全部操作。

總線和內存

現在,我們的計算機只不過是一個計算器,它記不住任何內容也對輸出沒有任何操作,上述電路只是接了一個显示單元而已。

上面展示的是一個存儲單元。它使用了大量的 NAND 門,並且在實際生產中,根據存儲技術的不同,它們可能會大不相同,但其功能是相同的。

您給它一些輸入,並打開“寫”位(Write 輸入 1),它將把輸入存儲在單元內。這不僅是一個存儲單元,因為我們還需要一種從中讀取信息的方法。這是通過一個使能器完成的,該使能器是「存儲器」中每個位的“與”門的集合,所有位都與另一個輸入(即“讀取”位)綁定在一起。寫入和讀取位通常也稱為“設置”(set)和“啟用”(enable)。

上面整個存儲單元都包裹在所謂的寄存器中。這些寄存器連接到 總線,總線是圍繞整個系統運行的一束電線,並連接到每個組件。即使現代計算機也具有總線,儘管它們可能具有多個總線以提高多任務處理性能。

每個寄存器仍有一個讀寫位,但是在這種設置下,輸入和輸出是一樣的。這實際上很好。例如:如果要將 R1 的內容複製到 R2,則應打開 R1 的讀取位,這會將 R1 的內容壓入總線。當讀取位打開時,您將打開 R2 的寫入位,這會將總線內容複製到 R2 中。

寄存器也用於製作 RAM。RAM 通常布置在網格中,並且導線有兩個方向:

解碼器採用二進制輸入並打開相應的編號線。例如,11 在二進制數中是 3,即最高的 2 位数字,因此解碼器將打開最高的線路。每個路口都有一個寄存器。所有這些都連接到中央總線以及中央寫入和讀取輸入。只有跨寄存器的兩條導線也都打開時,讀和寫輸入才會打開,從而有效地允許您選擇要從中進行讀寫的寄存器。同樣,現代 RAM 要複雜得多,但是此設置仍然有效。

時鐘,步進器和解碼器

寄存器無處不在,是在 CPU 中移動數據並將信息存儲在 CPU 中的基本工具。那麼,是什麼告訴他們移動數據的呢?

時鐘是 CPU 核心中的第一個組件,它將按設置的時間間隔(以赫茲或每秒周期為單位)關閉和打開。這就是您看到的最直觀的 CPU 速度指標。

時鐘具有三種不同的狀態:基本時鐘,使能時鐘和設置時鐘。基本時鐘將打開半個周期,另一半關閉。使能時鐘用於打開寄存器,並且需要更長的時間才能確保數據被使能。設置時鐘必須始終與使能時鐘同時打開,否則可能會寫入錯誤的數據。

時鐘連接到步進器,步進器將從 1 到最大步數進行計數,並在完成后將自身重置為 1。時鐘還連接到 CPU 可以寫入的每個寄存器的 AND 門:

這些 “與” 門還連接到另一個組件的輸出,即指令解碼器。指令解碼器接受 SET R2 TO R1 之類的指令,並將其解碼為 CPU 可以理解的內容。它有自己的內部寄存器,稱為“指令寄存器”,該寄存器存儲了當前操作。它的精確程度取決於您正在運行的系統,但是一旦解碼,它將打開正確的設置並啟用正確寄存器的位,這些寄存器將根據時鐘觸發。

程序指令存儲在 RAM(或現代系統中的 L1 高速緩存,更靠近 CPU)中。由於程序數據與其他所有變量一樣都存儲在寄存器中,因此可以隨時對其進行操作以在程序中跳轉。這就是程序通過循環和 if 語句獲取結構的方式。跳轉指令將指令解碼器正在讀取的存儲器中的當前位置設置到其他位置。

一切如何配合

現在,我們對 CPU 工作原理的有了一些基本的了解。主總線跨越整個系統,並連接到所有寄存器。完整的加法器以及其他一系列運算都打包在算術邏輯單元或 ALU 中。該 ALU 將與總線建立連接,並且還將具有自己的寄存器來存儲正在操作的第二個数字。

為了執行計算,將程序數據從系統 RAM 加載到控制部分。控制部分從 RAM 中讀取兩個数字,將第一個数字加載到 ALU 的指令寄存器中,然後將第二個数字加載到總線上。同時,它向 ALU 發送指令代碼,告知其操作方法。然後,ALU 執行所有計算,並將結果存儲在另一個寄存器中,CPU 可以從該寄存器中讀取該值,然後繼續該過程。

參考資料

  1. 原來,我們是這樣記數的 – https://www.jianshu.com/p/58844323e4fb
  2. 二進制數的運算方法 – https://www.jianshu.com/p/560aba49c9a4
  3. 文字,圖片,視頻,音頻的二進製表示 – https://blog.csdn.net/c46550/article/details/91040925
  4. 知乎 – 計算機只認識0和1但是怎麼表示圖像和影視等等眾多應用的? | @kross – https://www.zhihu.com/question/36269548
  5. Introduction to binary numbers – https://pmihaylov.com/intro-binary-numbers/
  6. What is Binary, and Why Do Computers Use It? – https://www.howtogeek.com/367621/what-is-binary-and-why-do-computers-use-it/
  7. CPU 是怎樣認識代碼的? | 知乎 – https://www.zhihu.com/question/348237008/answer/843382847 | @Zign
  8. HTG Explains: How Does a CPU Actually Work? – https://www.howtogeek.com/367931/htg-explains-how-does-a-cpu-actually-work/

往期推薦

  1. 「MoreThanJava」當大學選擇了計算機之後應該知道的
  2. 「MoreThanJava」計算機發展史—從織布機到IBM
  3. 「MoreThanJava」計算機系統概述
  4. 媽媽再也不擔心我面試被Redis問得臉都綠了
  • 本文已收錄至我的 Github 程序員成長系列 【More Than Java】,學習,不止 Code,歡迎 star:https://github.com/wmyskxz/MoreThanJava
  • 個人公眾號 :wmyskxz,個人獨立域名博客:wmyskxz.com,堅持原創輸出,下方掃碼關注,2020,與您共同成長!

非常感謝各位人才能 看到這裏,如果覺得本篇文章寫得不錯,覺得 「我沒有三顆心臟」有點東西 的話,求點贊,求關注,求分享,求留言!

創作不易,各位的支持和認可,就是我創作的最大動力,我們下篇文章見!

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

※別再煩惱如何寫文案,掌握八大原則!

什麼是銷售文案服務?A就是幫你撰寫適合的廣告文案。當您需要販售商品、宣傳活動、建立個人品牌,撰寫廣告文案都是必須的工作。

基於 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

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

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

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

HTTP 冷知識 | HTTP 請求中,空格應該被編碼為 %20 還是 + ?_網頁設計

台北網頁設計公司這麼多該如何選擇?

網動是一群專業、熱情、向前行的工作團隊,我們擁有靈活的組織與溝通的能力,能傾聽客戶聲音,激發創意的火花,呈現完美的作品

HTTP 請求中,空格應該被編碼為什麼?今天我們走進 RFC 文檔W3C 文檔,了解一下這個「史詩級」大坑。

1.%20 還是 +

開始講解前先看個小測試,在瀏覽器里輸入 blank testblanktest 間有個空格),我們看看瀏覽器如何處理的:

從動圖可以看出瀏覽器把空格解析為一個加號「+」。

是不是感覺有些奇怪?我們再做個測試,用瀏覽器提供的幾個函數試一下:

encodeURIComponent("blank test"// "blank%20test"
encodeURI("q=blank test")        // "q=blank%20test"
new URLSearchParams("q=blank test").toString() // "q=blank+test"

image-20200524184735653

代碼是不會說謊的,其實上面的結果都是正確的,encode 結果不一樣,是因為 URI 規範和 W3C 規範衝突了,才會搞出這種讓人疑惑的烏龍事件。

2.衝突的協議

我們首先看看 URI 中的保留字,這些保留字不參与編碼。保留字符一共有兩大類:

  • gen-delims:
    :
    /
    ?
    #
    [
    ]
    @
  • sub-delims:
    !
    $
    &
    '
    (
    )
    *
    +
    ,
    ;
    =

URI 的編碼規則也很簡單,先把非限定範圍的字符轉為 16 進制,然後前面加百分號。

空格這種不安全字符轉為十六進制就是 0x20,前面再加上百分號 % 就是 %20

image-20200524184601512

所以這時候再看 encodeURIComponentencodeURI 的編碼結果,就是完全正確的。

既然空格轉為%20 是正確的,那轉為 + 是怎麼回事?這時候我們就要了解一下 HTML form 表單的歷史。

早期的網頁沒有 AJAX 的時候,提交數據都是通過 HTML 的 form 表單。form 表單的提交方法可以用 GET 也可以用 POST,大家可以在 MDN form 詞條上測試:

網頁設計最專業,超強功能平台可客製化

窩窩以「數位行銷」「品牌經營」「網站與應用程式」「印刷品設計」等四大主軸,為每一位客戶客製建立行銷脈絡及洞燭市場先機。

經過測試我們可以看出表單提交的內容中,空格都是轉為加號的,這種編碼類型就是 application/x-www-form-urlencoded,在 WHATWG 規範里是這樣定義的:

image-20200524185912590

到這裏基本上就破案了,URLSearchParams 做 encode 的時候,就按這個規範來的。我找到了 URLSearchParams 的 Polyfill 代碼,裏面就做了 %20+ 的映射:

replace = {
    '!''%21',
    "'"'%27',
    '(''%28',
    ')''%29',
    '~''%7E',
    '%20''+'// <= 就是這個
    '%00''\x00'
}

規範里對這個編碼類型還有解釋說明:

The application/x-www-form-urlencoded format is in many ways an aberrant monstrosity, the result of many years of implementation accidents and compromises leading to a set of requirements necessary for interoperability, but in no way representing good design practices. In particular, readers are cautioned to pay close attention to the twisted details involving repeated (and in some cases nested) conversions between character encodings and byte sequences. Unfortunately the format is in widespread use due to the prevalence of HTML forms.

這種編碼方式就不是個好的設計,不幸的是隨着 HTML form 表單的普及,這種格式已經推廣開了

其實上面一大段句話就是一個意思:這玩意兒設計的就是 ,但積重難返,大家還是忍一下吧

3.一句話總結

  • URI 規範里,空格 encode 為 %20application/x-www-form-urlencoded 格式里,空格 encode 為 +

  • 實際業務開發時,最好使用業內成熟的 HTTP 請求庫封裝請求,這些雜活兒累活兒框架都幹了;

  • 如果非要使用原生 AJAX 提交 application/x-www-form-urlencoded 格式的數據,不要手動拼接參數,要用 URLSearchParams 處理數據,這樣可以避免各種噁心的編碼衝突。

4.文章推薦

本文選自我的長文HTTP 規範中的那些暗坑,想要了解更多可點擊原文查看。

更多推薦:

  • webpack 中最易混淆的 5 個知識點,掘金快 800 贊了
  • webpack dll 是個什麼東西,看完就能
    擺脫繁瑣的 dll 配置
  • React Native 性能優化指南從渲染層的角度分析了 RN 性能優化的 6 個點,並以圖文形式講解了 FlatList 的實現原理
  • Web Scraper——輕量數據爬取利器 介紹了一個小巧的瀏覽器爬蟲插件,可以實現簡單的數據爬取功能

最後推薦一下我的個人公眾號:「滷蛋實驗室」,平時會分享一些前端技術和數據分析的內容,大家感興趣的話可以關注一波:


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

※推薦評價好的iphone維修中心

擁有專業的維修技術團隊,同時聘請資深iphone手機維修專家,現場說明手機問題,快速修理,沒修好不收錢