linux中initrd的含義,Linux2.6 內核的 Initrd 機制解析

1.什么是 Initrdinitrd 的英文含義是 boot loaderinitialized RAM disk,就是由 boot loader 初始化的內存盤。在 linux內核啟動前, boot loader 會將存儲介質中的 initrd 文件加載到內存,內核啟動時會在訪問真正的根文件系統前先訪問該內存中的 initrd 文件系統。在 boot loader 配置了 initrd 的情況下,內核啟動被分成了兩個階段,第一階段先執行 initrd 文件系統中的"某個文件",完成加載驅動模塊等任務,第二階段才會執行真正的根文件系統中的 /sbin/init 進程。這里提到的"某個文件",Linux2.6 內核會同以前版本內核的不同,所以這里暫時使用了"某個文件"這個稱呼,后面會詳細講到。第一階段啟動的目的是為第二階段的啟動掃清一切障愛,最主要的是加載根文件系統存儲介質的驅動模塊。我們知道根文件系統可以存儲在包括IDE、SCSI、USB在內的多種介質上,如果將這些設備的驅動都編譯進內核,可以想象內核會多么龐大、臃腫。Initrd 的用途主要有以下四種:1. linux 發行版的必備部件linux 發行版必須適應各種不同的硬件架構,將所有的驅動編譯進內核是不現實的,initrd 技術是解決該問題的關鍵技術。Linux 發行版在內核中只編譯了基本的硬件驅動,在安裝過程中通過檢測系統硬件,生成包含安裝系統硬件驅動的 initrd,無非是一種即可行又靈活的解決方案。2. livecd 的必備部件同 linux 發行版相比,livecd 可能會面對更加復雜的硬件環境,所以也必須使用 initrd。3. 制作 Linux usb 啟動盤必須使用 initrdusb 設備是啟動比較慢的設備,從驅動加載到設備真正可用大概需要幾秒鐘時間。如果將 usb 驅動編譯進內核,內核通常不能成功訪問 usb 設備中的文件系統。因為在內核訪問 usb 設備時, usb 設備通常沒有初始化完畢。所以常規的做法是,在 initrd 中加載 usb 驅動,然后休眠幾秒中,等待 usb設備初始化完畢后再掛載 usb 設備中的文件系統。4. 在 linuxrc 腳本中可以很方便地啟用個性化 bootsplash。2.Linux2.4內核對 Initrd 的處理流程為了使讀者清晰的了解Linux2.6內核initrd機制的變化,在重點介紹Linux2.6內核initrd之前,先對linux2.4內核的initrd進行一個簡單的介紹。Linux2.4內核的initrd的格式是文件系統鏡像文件,本文將其稱為image-initrd,以區別后面介紹的linux2.6內核的cpio格式的initrd。 linux2.4內核對initrd的處理流程如下:1. boot loader把內核以及/dev/initrd的內容加載到內存,/dev/initrd是由boot loader初始化的設備,存儲著initrd。2. 在內核初始化過程中,內核把 /dev/initrd 設備的內容解壓縮并拷貝到 /dev/ram0 設備上。3. 內核以可讀寫的方式把 /dev/ram0 設備掛載為原始的根文件系統。4. 如果 /dev/ram0 被指定為真正的根文件系統,那么內核跳至最后一步正常啟動。5. 執行 initrd 上的 /linuxrc 文件,linuxrc 通常是一個腳本文件,負責加載內核訪問根文件系統必須的驅動, 以及加載根文件系統。6. /linuxrc 執行完畢,真正的根文件系統被掛載。7. 如果真正的根文件系統存在 /initrd 目錄,那么 /dev/ram0 將從 / 移動到 /initrd。否則如果 /initrd 目錄不存在, /dev/ram0 將被卸載。8. 在真正的根文件系統上進行正常啟動過程 ,執行 /sbin/init。 linux2.4 內核的 initrd 的執行是作為內核啟動的一個中間階段,也就是說 initrd 的 /linuxrc 執行以后,內核會繼續執行初始化代碼,我們后面會看到這是 linux2.4 內核同 2.6 內核的 initrd 處理流程的一個顯著區別。3.Linux2.6 內核對 Initrd 的處理流程linux2.6 內核支持兩種格式的 initrd,一種是前面第 3 部分介紹的 linux2.4 內核那種傳統格式的文件系統鏡像-image-initrd,它的制作方法同 Linux2.4 內核的 initrd 一樣,其核心文件就是 /linuxrc。另外一種格式的 initrd 是 cpio 格式的,這種格式的 initrd 從 linux2.5 起開始引入,使用 cpio 工具生成,其核心文件不再是 /linuxrc,而是 /init,本文將這種 initrd 稱為 cpio-initrd。盡管 linux2.6 內核對 cpio-initrd和 image-initrd 這兩種格式的 initrd 均支持,但對其處理流程有著顯著的區別,下面分別介紹 linux2.6 內核對這兩種 initrd 的處理流程。cpio-initrd 的處理流程1. boot loader 把內核以及 initrd 文件加載到內存的特定位置。2. 內核判斷initrd的文件格式,如果是cpio格式。3. 將initrd的內容釋放到rootfs中。4. 執行initrd中的/init文件,執行到這一點,內核的工作全部結束,完全交給/init文件處理。image-initrd的處理流程1. boot loader把內核以及initrd文件加載到內存的特定位置。2. 內核判斷initrd的文件格式,如果不是cpio格式,將其作為image-initrd處理。3. 內核將initrd的內容保存在rootfs下的/initrd.image文件中。4. 內核將/initrd.image的內容讀入/dev/ram0設備中,也就是讀入了一個內存盤中。5. 接著內核以可讀寫的方式把/dev/ram0設備掛載為原始的根文件系統。6. .如果/dev/ram0被指定為真正的根文件系統,那么內核跳至最后一步正常啟動。7. 執行initrd上的/linuxrc文件,linuxrc通常是一個腳本文件,負責加載內核訪問根文件系統必須的驅動, 以及加載根文件系統。8. /linuxrc執行完畢,常規根文件系統被掛載9. 如果常規根文件系統存在/initrd目錄,那么/dev/ram0將從/移動到/initrd。否則如果/initrd目錄不存在, /dev/ram0將被卸載。10. 在常規根文件系統上進行正常啟動過程 ,執行/sbin/init。通過上面的流程介紹可知,Linux2.6內核對image-initrd的處理流程同linux2.4內核相比并沒有顯著的變化, cpio-initrd的處理流程相比于image-initrd的處理流程卻有很大的區別,流程非常簡單,在后面的源代碼分析中,讀者更能體會到處理的簡捷。4.cpio-initrd同image-initrd的區別與優勢沒有找到正式的關于cpio-initrd同image-initrd對比的文獻,根據筆者的使用體驗以及內核代碼的分析,總結出如下三方面的區別,這些區別也正是cpio-initrd的優勢所在:cpio-initrd的制作方法更加簡單cpio-initrd的制作非常簡單,通過兩個命令就可以完成整個制作過程#假設當前目錄位于準備好的initrd文件系統的根目錄下bash# find . | cpio -c -o > ../initrd.imgbash# gzip ../initrd.img而傳統initrd的制作過程比較繁瑣,需要如下六個步驟#假設當前目錄位于準備好的initrd文件系統的根目錄下bash# dd if=/dev/zero of=../initrd.img bs=512k count=5bash# mkfs.ext2 -F -m0 ../initrd.imgbash# mount -t ext2 -o loop ../initrd.img /mntbash# cp -r * /mntbash# umount /mntbash# gzip -9 ../initrd.img本文不對上面命令的含義作細節的解釋,因為本文主要介紹的是linux內核對initrd的處理,對上面命令不理解的讀者可以參考相關文檔。cpio-initrd的內核處理流程更加簡化通過上面initrd處理流程的介紹,cpio-initrd的處理流程顯得格外簡單,通過對比可知cpio-initrd的處理流程在如下兩個方面得到了簡化:1. cpio-initrd并沒有使用額外的ramdisk,而是將其內容輸入到rootfs中,其實rootfs本身也是一個基于內存的文件系統。這樣就省掉了ramdisk的掛載、卸載等步驟。2. cpio-initrd啟動完/init進程,內核的任務就結束了,剩下的工作完全交給/init處理;而對于image-initrd,內核在執行完/linuxrc進程后,還要進行一些收尾工作,并且要負責執行真正的根文件系統的/sbin/init。通過圖1可以更加清晰的看出處理流程的區別:

圖1內核對cpio-initrd和image-initrd處理流程示意圖

461e14ec3061621dff9a35508c6a5768.gifcpio-initrd的職責更加重要如圖1所示,cpio-initrd不再象image-initrd那樣作為linux內核啟動的一個中間步驟,而是作為內核啟動的終點,內核將控制權交給cpio-initrd的/init文件后,內核的任務就結束了,所以在/init文件中,我們可以做更多的工作,而不比擔心同內核后續處理的銜接問題。當然目前linux發行版的cpio-initrd的/init文件的內容還沒有本質的改變,但是相信initrd職責的增加一定是一個趨勢。5.linux2.6內核initrd處理的源代碼分析上面簡要介紹了Linux2.4內核和2.6內核的initrd的處理流程,為了使讀者對于Linux2.6內核的initrd的處理有一個更加深入的認識,下面將對Linuxe2.6內核初始化部分同initrd密切相關的代碼給予一個比較細致的分析,為了講述方便,進一步明確幾個代碼分析中使用的概念:rootfs: 一個基于內存的文件系統,是linux在初始化時加載的第一個文件系統,關于它的進一步介紹可以參考文獻[4]。initramfs: initramfs同本文的主題關系不是很大,但是代碼中涉及到了initramfs,為了更好的理解代碼,這里對其進行簡單的介紹。Initramfs是在 kernel 2.5中引入的技術,實際上它的含義就是:在內核鏡像中附加一個cpio包,這個cpio包中包含了一個小型的文件系統,當內核啟動時,內核將這個cpio包解開,并且將其中包含的文件系統釋放到rootfs中,內核中的一部分初始化代碼會放到這個文件系統中,作為用戶層進程來執行。這樣帶來的明顯的好處是精簡了內核的初始化代碼,而且使得內核的初始化過程更容易定制。Linux 2.6.12內核的 initramfs還沒有什么實質性的東西,一個包含完整功能的initramfs的實現可能還需要一個緩慢的過程。對于initramfs的進一步了解可以參考文獻[1][2][3]。cpio-initrd: 前面已經定義過,指linux2.6內核使用的cpio格式的initrd。image-initrd: 前面已經定義過,專指傳統的文件鏡像格式的initrd。realfs: 用戶最終使用的真正的文件系統。內核的初始化代碼位于 init/main.c 中的 static int init(void * unused)函數中。同initrd的處理相關部分函數調用層次如下圖,筆者按照這個層次對每一個函數都給予了比較詳細的分析,為了更好的說明,下面列出的代碼中刪除了同本文主題不相關的部分:

圖2 initrd相關代碼的調用層次關系圖

6740a44bc5bdf869e247cf0ed7412df7.gifinit函數是內核所有初始化代碼的入口,代碼如下,其中只保留了同initrd相關部分的代碼。static int init(void * unused){[1]populate_rootfs();[2]if (sys_access((const char __user *) "/init", 0) == 0)execute_command = "/init";elseprepare_namespace();[3]if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)printk(KERN_WARNING "Warning: unable to open an initial console.\n");(void) sys_dup(0);(void) sys_dup(0);[4]if (execute_command)run_init_process(execute_command);run_init_process("/sbin/init");run_init_process("/etc/init");run_init_process("/bin/init");run_init_process("/bin/sh");panic("No init found. Try passing init= option to kernel.");}代碼[1]:populate_rootfs函數負責加載initramfs和cpio-initrd,對于populate_rootfs函數的細節后面會講到。代碼[2]:如果rootfs的根目錄下中包含/init進程,則賦予execute_command,在init函數的末尾會被執行。否則執行prepare_namespace函數,initrd是在該函數中被加載的。代碼[3]:將控制臺設置為標準輸入,后續的兩個sys_dup(0),則復制標準輸入為標準輸出和標準錯誤輸出。代碼[4]:如果rootfs中存在init進程,就將后續的處理工作交給該init進程。其實這段代碼的含義是如果加載了cpio-initrd則交給cpio-initrd中的/init處理,否則會執行realfs中的init。讀者可能會問:如果加載了cpio-initrd, 那么realfs中的init進程不是沒有機會運行了嗎?確實,如果加載了cpio-initrd,那么內核就不負責執行realfs的init進程了,而是將這個執行任務交給了cpio-initrd的init進程。解開fedora core4的initrd文件,會發現根目錄的下的init文件是一個腳本,在該腳本的最后一行有這樣一段代碼:………..switchroot --movedev /sysroot就是switchroot語句負責加載realfs,以及執行realfs的init進程。對cpio-initrd的處理對cpio-initrd的處理位于populate_rootfs函數中。void __init populate_rootfs(void){[1] char *err = unpack_to_rootfs(__initramfs_start,__initramfs_end - __initramfs_start, 0);[2]if (initrd_start) {[3]err = unpack_to_rootfs((char *)initrd_start,initrd_end - initrd_start, 1);[4]if (!err) {printk(" it is\n");unpack_to_rootfs((char *)initrd_start,initrd_end - initrd_start, 0);free_initrd_mem(initrd_start, initrd_end);return;}[5]fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 700);if (fd >= 0) {sys_write(fd, (char *)initrd_start,initrd_end - initrd_start);sys_close(fd);free_initrd_mem(initrd_start, initrd_end);}}代碼[1]:加載initramfs, initramfs位于地址__initramfs_start處,是內核在編譯過程中生成的,initramfs的是作為內核的一部分而存在的,不是 boot loader加載的。前面提到了現在initramfs沒有任何實質內容。代碼[2]:判斷是否加載了initrd。無論哪種格式的initrd,都會被boot loader加載到地址initrd_start處。代碼[3]:判斷加載的是不是cpio-initrd。實際上 unpack_to_rootfs有兩個功能一個是釋放cpio包,另一個就是判斷是不是cpio包, 這是通過最后一個參數來區分的, 0:釋放 1:查看。代碼[4]:如果是cpio-initrd則將其內容釋放出來到rootfs中。代碼[5]:如果不是cpio-initrd,則認為是一個image-initrd,將其內容保存到/initrd.image中。在后面的image-initrd的處理代碼中會讀取/initrd.image。對image-initrd的處理 在prepare_namespace函數里,包含了對image-initrd進行處理的代碼,相關代碼如下:void __init prepare_namespace(void){[1]if (initrd_load())goto out;out:umount_devfs("/dev");[2]sys_mount(".", "/", NULL, MS_MOVE, NULL);sys_chroot(".");security_sb_post_mountroot();mount_devfs_fs ();}代碼[1]:執行initrd_load函數,將initrd載入,如果載入成功的話initrd_load函數會將realfs的根設置為當前目錄。代碼[2]:將當前目錄即realfs的根mount為Linux VFS的根。initrd_load函數執行完后,將真正的文件系統的根設置為當前目錄。initrd_load函數負責載入image-initrd,代碼如下:int __init initrd_load(void){[1]if (mount_initrd) {create_dev("/dev/ram", Root_RAM0, NULL);[2]if (rd_load_image("/initrd.image") && ROOT_DEV != Root_RAM0) {sys_unlink("/initrd.image");handle_initrd();return 1;}}sys_unlink("/initrd.image");return 0;}代碼[1]:如果加載initrd則建立一個ram0設備 /dev/ram。代碼[2]:/initrd.image文件保存的就是image-initrd,rd_load_image函數執行具體的加載操作,將image-nitrd的文件內容釋放到ram0里。判斷ROOT_DEV!=Root_RAM0的含義是,如果你在grub或者lilo里配置了 root=/dev/ram0 ,則實際上真正的根設備就是initrd了,所以就不把它作為initrd處理 ,而是作為realfs處理。handle_initrd()函數負責對initrd進行具體的處理,代碼如下:static void __init handle_initrd(void){[1]real_root_dev = new_encode_dev(ROOT_DEV);[2]create_dev("/dev/root.old", Root_RAM0, NULL);mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY);[3]sys_mkdir("/old", 0700);root_fd = sys_open("/", 0, 0);old_fd = sys_open("/old", 0, 0);/* move initrd over / and chdir/chroot in initrd root */[4]sys_chdir("/root");sys_mount(".", "/", NULL, MS_MOVE, NULL);sys_chroot(".");mount_devfs_fs ();[5]pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);if (pid > 0) {while (pid != sys_wait4(-1, &i, 0, NULL))yield();}/* move initrd to rootfs' /old */sys_fchdir(old_fd);sys_mount("/", ".", NULL, MS_MOVE, NULL);/* switch root and cwd back to / of rootfs */[6]sys_fchdir(root_fd);sys_chroot(".");sys_close(old_fd);sys_close(root_fd);umount_devfs("/old/dev");[7]if (new_decode_dev(real_root_dev) == Root_RAM0) {sys_chdir("/old");return;}[8]ROOT_DEV = new_decode_dev(real_root_dev);mount_root();[9]printk(KERN_NOTICE "Trying to move old root to /initrd ... ");error = sys_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL);if (!error)printk("okay\n");else {int fd = sys_open("/dev/root.old", O_RDWR, 0);printk("failed\n");printk(KERN_NOTICE "Unmounting old root\n");sys_umount("/old", MNT_DETACH);printk(KERN_NOTICE "Trying to free ramdisk memory ... ");if (fd < 0) {error = fd;} else {error = sys_ioctl(fd, BLKFLSBUF, 0);sys_close(fd);}printk(!error ? "okay\n" : "failed\n");}handle_initrd函數的主要功能是執行initrd的linuxrc文件,并且將realfs的根目錄設置為當前目錄。代碼[1]:real_root_dev,是一個全局變量保存的是realfs的設備號。代碼[2]:調用mount_block_root函數將initrd文件系統掛載到了VFS的/root下。代碼[3]:提取rootfs的根的文件描述符并將其保存到root_fd。它的作用就是為了在chroot到initrd的文件系統,處理完initrd之后要,還能夠返回rootfs。返回的代碼參考代碼[7]。代碼[4]:chroot進入initrd的文件系統。前面initrd已掛載到了rootfs的/root目錄。代碼[5]:執行initrd的linuxrc文件,等待其結束。代碼[6]:initrd處理完之后,重新chroot進入rootfs。代碼[7]:如果real_root_dev在 linuxrc中重新設成Root_RAM0,則initrd就是最終的realfs了,改變當前目錄到initrd中,不作后續處理直接返回。代碼[8]:在linuxrc執行完后,realfs設備已經確定,調用mount_root函數將realfs掛載到root_fs的 /root目錄下,并將當前目錄設置為/root。代碼[9]:后面的代碼主要是做一些收尾的工作,將initrd的內存盤釋放。到此代碼分析完畢。6.結束語通過本文前半部分對cpio-initrd和imag-initrd的闡述與對比以及后半部分的代碼分析,我相信讀者對Linux 2.6內核的initrd技術有了一個較為全面的了解。在本文的最后,給出兩點最重要的結論:1. 盡管Linux2.6既支持cpio-initrd,也支持image-initrd,但是cpio-initrd有著更大的優勢,在使用中我們應該優先考慮使用cpio格式的initrd。2. cpio-initrd相對于image-initrd承擔了更多的初始化責任,這種變化也可以看作是內核代碼的用戶層化的一種體現,我們在其它的諸如FUSE等項目中也看到了將內核功能擴展到用戶層實現的嘗試。精簡內核代碼,將部分功能移植到用戶層必然是linux內核發展的一個趨勢。參考資料從下面三篇文章中,可以獲得更多的關于initramfs的知識:[1][2][3]從下面這篇文章中讀者可以了解到關于linux VSF、rootfs的相關知識:[4] http://www.ibm.com/developerworks/cn/linux/l-vfs/下面是一些initrd的參考資料:[5]關于作者李大治,軟件工程師,目前從事Linux平臺下網絡安全產品的開發工作,您可以通過dazhi.li@gmail.com同他取得聯系。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/395461.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/395461.shtml
英文地址,請注明出處:http://en.pswp.cn/news/395461.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

VBS基礎篇 - 常量

VBS基礎篇 - 常量 常量&#xff1a;指的是在程序運行過程中其值保持不變的量&#xff0c;它用來保存固定不變的數值&#xff0c;字符串等常數 。 常量的定義&#xff1a;在vbscript中使用使用 Const 指令可以創建名稱具有一定含義的字符串型或數值型常量&#xff0c;并給它們賦…

為什么虛擬助手的前途一片光明

by Steve史蒂夫(Steve) 為什么虛擬助手的前途一片光明 (Why the future is bright for Virtual Assistants) I purchased my first mobile phone in the summer of 1999. I was 17 years old, growing up in a nondescript town in the Midlands of the United Kingdom. The p…

利用深度學習來預測股票價格變動

https://www.toutiao.com/i6644852565341110791/ 利用深度學習來預測股票價格變動&#xff08;長文&#xff0c;建議收藏&#xff09; 原創 不靠譜的貓 2019-01-10 21:01:39完整架構概述 在這篇文章中&#xff0c;我將創建一個預測股票價格變動的完整過程。我們將使用生成對抗網…

C語言 用鏈表對學號進行排序,求解C語言中建立一個對鏈表按照學號進行排序的問題...

功能&#xff1a;選擇排序(由小到大)返回&#xff1a;指向鏈表表頭的指針*//*選擇排序的基本思想就是反復從還未排好序的那些節點中&#xff0c;選出鍵值(就是用它排序的字段&#xff0c;我們取學號num為鍵值)最小的節點&#xff0c;依次重新組合成一個鏈表。我認為寫鏈表這類程…

字符集(CHARACTER SET)和校對集(COLLATE)

http://blog.sina.com.cn/s/blog_9707fac301016wxm.html http://www.th7.cn/db/mysql/201412/84636.shtml 從上文中可以看出character_set_connection、character_set_client、 character_set_results三個字符集什么時候用到。從實際上可以看到&#xff0c;當客戶端連接服務器的…

shell 本地接口自動化

一.基于http/https的接口 一般情況下&#xff0c;當前大多公司在做接口自動化的時候都會使用一些工具&#xff1b;比如&#xff1a;postman/jmeter/python自研開發接口平臺。。。 以上的情況&#xff0c;都是在源碼與測試使用分離的情況下實踐的。也就是說&#xff1a;目前國內…

hitchhiker部署_《 Hitchhiker的Python機器學習指南》

hitchhiker部署by Conor Dewey由Conor Dewey 《 Hitchhiker的Python機器學習指南》 (The Hitchhiker’s Guide to Machine Learning in Python) 提供實施代碼&#xff0c;教學視頻等 (Featuring implementation code, instructional videos, and more) 趨勢 (The Trend) Machi…

CAD庫中列舉所有航路點

select distinct f1.airway_point_name,f1.latitude,f1.longitude,upper(f1.airway_point_type_name)type,f2.code_fir from airway_ordered_point f1, v_airway_point f2where f2.significant_point_idf1.airway_point_idorder by code_fir, type,airway_point_name轉載于:htt…

第50次二級c語言真題,2006年4月全國計算機等級考試二級C語言筆試試卷含答案

一、選擇題((1)一(10)每題2分&#xff0c;(11)一(50)每題1分&#xff0c;共60分)下列各題A)、B)、C)、D)四個選項中&#xff0c;只有一個選項是正確的&#xff0c;請將正確選項涂寫在答題卡相應位置上&#xff0c;答在試卷上不得分。(1)下列選項中不屬于結構化程序設計方法的是…

python hashlib模塊

摘要算法簡介 Python的hashlib提供了常見的摘要算法&#xff0c;如MD5&#xff0c;SHA1等等。 什么是摘要算法呢&#xff1f;摘要算法又稱哈希算法、散列算法。它通過一個函數&#xff0c;把任意長度的數據轉換為一個長度固定的數據串&#xff08;通常用16進制的字符串表示&…

TZOJ 5101 A Game(區間DP)

描述 Consider the following two-player game played with a sequence of N positive integers (2 < N < 100) laid onto a 1 x N game board. Player 1 starts the game. The players move alternately by selecting a number from either the left or the right end o…

國家職業標準職業編碼查詢_為什么我學會編碼而不是從事金融職業

國家職業標準職業編碼查詢by Amir Ghafouri通過阿米爾加富里(Amir Ghafouri) 為什么我學會編碼而不是從事金融職業 (Why I learned to code instead of pursuing a career in finance) Last year I faced a major life and career decision: commit to pursuing a Chartered F…

go tool trace goalng調優工具

為什么80%的碼農都做不了架構師&#xff1f;>>> 你想知道你的Go程序在做什么嗎&#xff1f; go tool trace 可以向你揭示&#xff1a;Go程序運行中的所有的運行時事件。 這種工具是Go生態系統中用于診斷性能問題時&#xff08;如延遲&#xff0c;并行化和競爭異常…

程序員 文本編輯器 c語言,程序員必備的五款文本編輯器

原標題&#xff1a;程序員必備的五款文本編輯器程序員的工作離不開文本編輯器&#xff0c;有人說一個txt就能搞定&#xff0c;但txt面對如今復雜的要求&#xff0c;明顯有些捉襟見肘&#xff0c;下面推薦五款超級好用的文本編輯器及搭配軟件&#xff0c;絕對是程序員的大愛。程…

PCH文件的創建和配置

1.PCH文件的的創建 (1)CommandN (2)打開新建文件窗口:ios->other->PCH file&#xff0c;創建一個pch文件 2.PCH文件的配置 (1)在工程的TARGETS里邊Building Setting中搜索Prefix Header (2)然后在Precompile Prefix Header下邊的Prefix Header右邊雙擊&#xff0c;添加剛…

ci 數據庫異常捕獲_系統地捕獲錯誤:如何通過4個步驟構建GitLab CI測試管道

ci 數據庫異常捕獲by Joyz通過喬伊斯 系統地捕獲錯誤&#xff1a;如何通過4個步驟構建GitLab CI測試管道 (Catch bugs systematically: how to build a GitLab CI testing pipeline in 4 steps) Your first app is a hit the day it’s launched. But one week later, you rea…

(小白)函數一: 聲明函數的方法—語句定義法和表達式定義法的區別

一、函數的定義&#xff1a; 在說明什么是函數前先舉一個小例子&#xff1a; 大家都知道印刷術是我國的四大發明&#xff08;科普一下&#xff1a;中國四大發明&#xff1a;造紙術、印刷術、火藥、指南針&#xff09;之一&#xff0c;之所以有印刷術&#xff0c;是因為重復的抄…

android限制輸入字符的范圍,Android EditText 對輸入字數和內容范圍進行限制

在做定制機時&#xff0c;對光敏值進行范圍控制時&#xff0c;以及對區號輸入時遇到對輸入字數以及輸入內容的顯示。找了好多方法&#xff0c;終于找到了幾種方法其中EditText的addTextChangedListener功不可沒。例如對光敏值要在0到61之間。大于61時要在輸入框中自動變為61.代…

vue13過濾器 debounce延遲、limitBy、filterBy、orderBy

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>智能社——http://www.zhinengshe.com</title><meta name"viewport" content"widthdevice-width, initial-scale1.0, maximum…

Sass:一種CSS預處理器語言

http://sass-lang.com/ Sass是一種CSS預處理器語言&#xff0c;通過編程方式生成CSS代碼。因為可編程&#xff0c;所以操控靈活性自由度高&#xff0c;方便實現一些直接編寫CSS代碼較困難的代碼。 同時&#xff0c;因為Sass是生成CSS的語言&#xff0c;所以寫出來的Sass文件是不…