深究標準IO的緩存

前言

  在最近看了APUE的標準IO部分之后感覺對標準IO的緩存太模糊,沒有搞明白,APUE中關于緩存的部分一筆帶過,沒有深究緩存的實現原理,這樣一本被吹上天的書為什么不講透徹呢?今天早上爬起來趕緊找了幾篇文章看看,直到發現了這篇博客:http://blog.sina.com.cn/s/blog_6592a07a0101gar7.html。講的很不錯。

一、IO緩存

  系統調用:只操作系統提供給用戶程序調用的一組接口-------獲得內核提供的服務。

在實際中程序員使用的通常不是系統調用,而是用戶編程接口API,也稱為系統調用編程接口。它是遵循Posix標準(Portable operation system interface),API函數可能要一個或者幾個系統調用才能完成函數功能,此函數通過c庫(libc)實現,如read,open。
  fsync是把內核緩沖刷到磁盤上。
  fflush:是把C庫中的緩沖調用write函數寫到磁盤[其實是寫到內核的緩沖區]。
linux對IO文件的操作分為:
  • 不帶緩存:open ?read。posix標準,在用戶空間沒有緩沖,在內核空間還是進行了緩存的。數據-----內核緩存區----磁盤。假設內核緩存區長度為100字節,你調用ssize_t write (int fd,const void * buf,size_t count);寫操作時,設每次寫入count=10字節,那么你要調用10次這個函數才能把這個緩存區寫滿,沒寫滿時數據還是在內核緩沖區中,并沒有寫入到磁盤中,內核緩存區滿了之后或者執行了fsync(強制寫入硬盤)之后,才進行實際的IO操作,吧數據寫入磁盤上。
  • 帶緩存區:fopen fwrite fget 等,是c標準庫中定義的。數據-----流緩存區-----內核緩存區----磁盤。假設流緩存區長度為50字節,內核緩存區100字節,我們用標準c庫函數fwrite()將數據寫入到這個流緩存中,每次寫10字節,需要寫5次流緩存區滿后調用write()(或調用fflush()),將數據寫到內核緩存區,直到內核緩存區滿了之后或者執行了fsync(強制寫入硬盤)之后,才進行實際的IO操作,吧數據寫入磁盤上。標準IO操作fwrite()最后還是要掉用無緩存IO操作write。

  以fgetc / fputc 為例,當用戶程序第一次調用fgetc 讀一個字節時,fgetc 函數可能通過系統調用 進入內核讀1K字節到I/O緩沖區中,然后返回I/O緩沖區中的第一個字節給用戶,把讀寫位置指 向I/O緩沖區中的第二個字符,以后用戶再調fgetc ,就直接從I/O緩沖區中讀取,而不需要進內核 了,當用戶把這1K字節都讀完之后,再次調用fgetc 時,fgetc 函數會再次進入內核讀1K字節 到I/O緩沖區中。在這個場景中用戶程序、C標準庫和內核之間的關系就像在“Memory Hierarchy”中 CPU、Cache和內存之間的關系一樣,C標準庫之所以會從內核預讀一些數據放 在I/O緩沖區中,是希望用戶程序隨后要用到這些數據,C標準庫的I/O緩沖區也在用戶空間,直接 從用戶空間讀取數據比進內核讀數據要快得多。另一方面,用戶程序調用fputc 通常只是寫到I/O緩 沖區中,這樣fputc 函數可以很快地返回,如果I/O緩沖區寫滿了,fputc 就通過系統調用把I/O緩沖 區中的數據傳給內核,內核最終把數據寫回磁盤或設備。有時候用戶程序希望把I/O緩沖區中的數據立刻 傳給內核,讓內核寫回設備或磁盤,這稱為Flush操作,對應的庫函數是fflush,fclose函數在關閉文件 之前也會做Flush操作。

  雖然write 系統調用位于C標準庫I/O緩沖區的底 層,被稱為Unbuffered I/O函數,但在write 的底層也可以分配一個內核I/O緩沖區,所以write 也不一定是直接寫到文件的,也 可能寫到內核I/O緩沖區中,可以使用fsync函數同步至磁盤文件,至于究竟寫到了文件中還是內核緩沖區中對于進程來說是沒有差別 的,如果進程A和進程B打開同一文件,進程A寫到內核I/O緩沖區中的數據從進程B也能讀到,因為內核空間是進程共享的, 而c標準庫的I/O緩沖區則不具有這一特性,因為進程的用戶空間是完全獨立的.

?

下面是一個利用buffered I/O讀取數據的例子:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main(void)
{char buf[5];FILE *myfile = stdin;fgets(buf, 5, myfile);fputs(buf, myfile);return 0;
}

  buffered I/O中的"buffer"到底是指什么呢?這個buffer在什么地方呢?FILE是什么呢?它的空間是怎么分配的呢  要弄清楚這些問題,就要看看FILE是如何定義和運作的了.(特別說明,在平時寫程序時,不用也不要關心FILE是如何定義和運作的,最好不要直接操作它,這里使用它,只是為了說明buffered IO)下面的這個是glibc給出的FILE的定義,它是實現相關的,別的平臺定義方式不同.

struct _IO_FILE {
int _flags;
#define _IO_file_flags _flagschar* _IO_read_ptr;
char* _IO_read_end;
char* _IO_read_base;
char* _IO_write_base;
char* _IO_write_ptr;
char* _IO_write_end;
char* _IO_buf_base;
char* _IO_buf_end;char *_IO_save_base;
char *_IO_backup_base;
char *_IO_save_end;struct _IO_marker *_markers;struct _IO_FILE *_chain;int _fileno;
};

  上面的定義中有三組重要的字段:

1.
char* _IO_read_ptr;
char* _IO_read_end;
char* _IO_read_base;
2.
char* _IO_write_base;
char* _IO_write_ptr;
char* _IO_write_end;
3.
char* _IO_buf_base;
char* _IO_buf_end;
其中,
  _IO_read_base 指向"讀緩沖區"
  _IO_read_end??指向"讀緩沖區"的末尾
  _IO_read_end - _IO_read_base "讀緩沖區"的長度

  _IO_write_base 指向"寫緩沖區"
  _IO_write_end 指向"寫緩沖區"的末尾
  _IO_write_end - _IO_write_base "寫緩沖區"的長度

  _IO_buf_base??指向"緩沖區"
  _IO_buf_end???指向"緩沖區"的末尾
  _IO_buf_end - _IO_buf_base "緩沖區"的長度

  上面的定義貌似給出了3個緩沖區,實際上上面的_IO_read_base,_IO_write_base, _IO_buf_base都指向了同一個緩沖區.這個緩沖區跟上面程序中的char buf[5];沒有任何關系.他們在第一次buffered I/O操作時由庫函數自動申請空間,最后由相應庫函數負責釋放.(再次聲明,這里只是glibc的實現,別的實現可能會不同,后面就不再強調了)

  請看下面的程序(這里給的是stdin,行緩沖的例子):
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main(void)
{char buf[5];FILE *myfile =stdin;printf("before reading/n");printf("read buffer base %p/n", myfile->_IO_read_base);printf("read buffer length %d/n", myfile->_IO_read_end - myfile->_IO_read_base);printf("write buffer base %p/n", myfile->_IO_write_base);printf("write buffer length %d/n", myfile->_IO_write_end - myfile->_IO_write_base);printf("buf buffer base %p/n", myfile->_IO_buf_base);printf("buf buffer length %d/n", myfile->_IO_buf_end - myfile->_IO_buf_base);printf("/n");fgets(buf, 5, myfile);fputs(buf, myfile);printf("/n");printf("after reading/n");printf("read buffer base %p/n", myfile->_IO_read_base);printf("read buffer length %d/n", myfile->_IO_read_end - myfile->_IO_read_base);printf("write buffer base %p/n", myfile->_IO_write_base);printf("write buffer length %d/n", myfile->_IO_write_end - myfile->_IO_write_base);printf("buf buffer base %p/n", myfile->_IO_buf_base);printf("buf buffer length %d/n", myfile->_IO_buf_end - myfile->_IO_buf_base);return 0;
}

  可以看到,在讀操作之前,myfile的緩沖區是沒有被分配的,在一次讀之后,myfile的緩沖區才被分配.這個緩沖區既不是內核中的緩沖區,也不是用戶分配的緩沖區,而是有用戶進程空間中的由buffered I/O系統負責維護的緩沖區.(當然,用戶可以可以維護該緩沖區,這里不做討論了)

上面的例子只是說明了buffered I/O緩沖區的存在,下面從全緩沖,行緩沖和無緩沖3個方面看一下buffered I/O是如何工作的.


二、 全緩沖

  下面是APUE上的原話:全緩沖"在填滿標準I/O緩沖區后才進行實際的I/O操作.對于駐留在磁盤上的文件通常是由標準I/O庫實施全緩沖的"書中這里"實際的I/O操作"實際上容易引起誤導,這里并不是讀寫磁盤,而應該是進行read或write的系統調用,下面兩個例子會說明這個問題:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main(void)
{char buf[5];char *cur;FILE *myfile;myfile = fopen("bbb.txt", "r");printf("before reading, myfile->_IO_read_ptr: %d/n", myfile->_IO_read_ptr - myfile->_IO_read_base);fgets(buf, 5, myfile); //僅僅讀4個字符cur = myfile->_IO_read_base;while (cur <</span> myfile->_IO_read_end) //實際上讀滿了這個緩沖區
  {printf("%c",*cur);cur++;}printf("/nafter reading, myfile->_IO_read_ptr: %d/n", myfile->_IO_read_ptr - myfile->_IO_read_base);return 0;
}

  上面提到的bbb.txt文件的內容是由很多行的"123456789"組成上例中,fgets(buf, 5, myfile); 僅僅讀4個字符,但是,緩沖區已被寫滿,但是_IO_read_ptr卻向前移動了5位,下次再次調用讀操作時,只要要讀的位數不超過myfile->_IO_read_end - myfile->_IO_read_ptr那么就不需要再次調用系統調用read,只要將數據從myfile的緩沖區拷貝到buf即可(從myfile->_IO_read_ptr開始拷貝)

全緩沖讀的時候,_IO_read_base始終指向緩沖區的開始,_IO_read_end始終指向已從內核讀入緩沖區的字符的下一個(對全緩沖來說,buffered I/O讀每次都試圖都將緩沖區讀滿),IO_read_ptr始終指向緩沖區中已被用戶讀走的字符的下一個(_IO_read_end < (_IO_buf_base-_IO_buf_end)) && (_IO_read_ptr == _IO_read_end)時則已經到達文件末尾其中_IO_buf_base-_IO_buf_end是緩沖區的長度
  一般大體的工作情景為:第一次fgets(或其他的)時,標準I/O會調用read將緩沖區充滿,下一次fgets不調用read而是直接從該緩沖區中拷貝數據,直到緩沖區的中剩余的數據不夠時,再次調用read.在這個過程中,_IO_read_ptr就是用來記錄緩沖區中哪些數據是已讀的,
哪些數據是未讀的.
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main(void)
{char buf[2048]={0};int i;FILE *myfile;myfile = fopen("aaa.txt", "r+");i= 0;while (i<</span>2048){fwrite(buf+i, 1, 512, myfile);i +=512;//注釋掉這句則可以寫入aaa.txtmyfile->_IO_write_ptr = myfile->_IO_write_base;printf("%p write buffer base/n", myfile->_IO_write_base);printf("%p buf buffer base /n", myfile->_IO_buf_base);printf("%p read buffer base /n", myfile->_IO_read_base);printf("%p write buffer ptr /n", myfile->_IO_write_ptr);printf("/n");}return 0;
}

  上面這個是關于全緩沖寫的例子.全緩沖時,只有當標準I/O自動flush(比如當緩沖區已滿時)或者手工調用fflush時,標準I/O才會調用一次write系統調用.例子中,fwrite(buf+i, 1, 512, myfile);這一句只是將buf+i接下來的512個字節寫入緩沖區,由于緩沖區未滿,標準I/O并未調用write.此時,myfile->_IO_write_ptr = myfile->_IO_write_base;會導致標準I/O認為沒有數據寫入緩沖區,所以永遠不會調用write,這樣aaa.txt文件得不到寫入.注釋掉myfile->_IO_write_ptr = myfile->_IO_write_base;前后,看看效果

全緩沖寫的時候:_IO_write_base始終指向緩沖區的開始,_IO_write_end全緩沖的時候,始終指向緩沖區的最后一個字符的下一個(對全緩沖來說,buffered I/O寫總是試圖在緩沖區寫滿之后,再系統調用write),_IO_write_ptr始終指向緩沖區中已被用戶寫入的字符的下一個,flush的時候,將_IO_write_base和_IO_write_ptr之間的字符通過系統調用write寫入內核


三、 行緩沖

  下面是APUE上的原話:行緩沖"當輸入輸出中遇到換行符時,標準I/O庫執行I/O操作. "書中這里"執行O操作"也容易引起誤導,這里不是讀寫磁盤,而應該是進行read或write的系統調用
  下面兩個例子會說明這個問題
  第一個例子可以用來說明下面這篇帖子的問題
http://bbs.chinaunix.net/viewthread.php?tid=954547
  
#include <stdlib.h>
#include <stdio.h>int main(void)
{char buf[5];char buf2[10];fgets(buf, 5, stdin); //第一次輸入時,超過5個字符
puts(stdin->_IO_read_ptr);//本句說明整行會被一次全部讀入緩沖區,//而非僅僅上面需要的個字符stdin->_IO_read_ptr = stdin->_IO_read_end; //標準I/O會認為緩沖區已空,再次調用read//注釋掉,再看看效果printf("/n");puts(buf);fgets(buf2, 10, stdin);puts(buf2);return 0;
}

  上例中, fgets(buf, 5, stdin); 僅僅需要4個字符,但是,輸入行中的其他數據也被寫入緩沖區,但是_IO_read_ptr向前移動了5位,下次再次調用fgets操作時,就不需要再次調用系統調用read,只要將數據從stdin的緩沖區拷貝到buf2即可(從stdin->_IO_read_ptr開始拷貝)stdin->_IO_read_ptr = stdin->_IO_read_end;會導致標準I/O會認為緩沖區已空,再次fgets則需要再次調用read.比較一下將該句注釋掉前后的效果


  
行緩沖讀的時候,
  _IO_read_base始終指向緩沖區的開始
  _IO_read_end始終指向已從內核讀入緩沖區的字符的下一個
  _IO_read_ptr始終指向緩沖區中已被用戶讀走的字符的下一個
  (_IO_read_end < (_IO_buf_base-_IO_buf_end)) && (_IO_read_ptr == _IO_read_end)時則已經到達文件末尾
  其中_IO_buf_base-_IO_buf_end是緩沖區的長度
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>char buf[5]={'1','2', '3', '4', '5'}; //最后一個不要是/n,是/n的話,標準I/O會自動flush的//這是行緩沖跟全緩沖的重要區別void writeLog(FILE *ftmp)
{fprintf(ftmp, "%p write buffer base/n", stdout->_IO_write_base);fprintf(ftmp, "%p buf buffer base /n", stdout->_IO_buf_base);fprintf(ftmp, "%p read buffer base /n", stdout->_IO_read_base);fprintf(ftmp, "%p write buffer ptr /n", stdout->_IO_write_ptr);fprintf(ftmp, "/n");
}int main(void)
{int i;FILE *ftmp;ftmp = fopen("ccc.txt", "w");i= 0;while (i<</span>4){fwrite(buf, 1, 5, stdout);i++;*stdout->_IO_write_ptr++ = '/n';//可以單獨把這句打開,看看效果//getchar();//getchar()會標準I/O將緩沖區輸出//打開下面的注釋,你就會發現屏幕上什么輸出也沒有//stdout->_IO_write_ptr = stdout->_IO_write_base;writeLog(ftmp); //這個只是為了查看緩沖區指針的變化  
  }return 0;
}

  這個例子將將FILE結構中指針的變化寫入的文件ccc.txt,

  運行后可以有興趣的話,可以看看.

  上面這個是關于行緩沖寫的例子.stdout->_IO_write_ptr = stdout->_IO_write_base;會使得標準I/O認為緩沖區是空的,從而沒有任何輸出.可以將上面程序中的注釋分別去掉,看看運行結果

  行緩沖時,下面3個條件之一會導致緩沖區立即被flush
  1. 緩沖區已滿
  2. 遇到一個換行符;比如將上面例子中buf[4]改為'/n'時
  3. 再次要求從內核中得到數據時;比如上面的程序加上getchar()會導致馬上輸出

  行緩沖寫的時候:
  _IO_write_base始終指向緩沖區的開始
  _IO_write_end始終指向緩沖區的開始
  _IO_write_ptr始終指向緩沖區中已被用戶寫入的字符的下一個

  flush的時候,將_IO_write_base和_IO_write_ptr之間的字符通過系統調用write寫入內核

四、無緩沖

  無緩沖時,標準I/O不對字符進行緩沖存儲.典型代表是stderr。這里的無緩沖,并不是指緩沖區大小為0,其實,還是有緩沖的,大小為1
#include <</span>stdlib.h>
#include <</span>stdio.h>
#include <</span>sys/types.h>
#include <</span>sys/stat.h>
#include <</span>fcntl.h>int main(void)
{fputs("stderr", stderr);printf("%d/n", stderr->_IO_buf_end - stderr->_IO_buf_base);return 0;
}

  對無緩沖的流的每次讀寫操作都會引起系統調用


五、 feof的問題

  這里從緩沖區的角度去考察一下.對于一個空文件,為什么要先讀一下,才能用feof判斷出該文件到了結尾了呢?
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main(void)
{char buf[5];char buf2[10];fgets(buf, sizeof(buf), stdin);//輸入要于4個,少于13個字符才能看出效果
  puts(buf);//交替注釋下面兩行//stdin->_IO_read_end = stdin->_IO_read_ptr+1;
stdin->_IO_read_end = stdin->_IO_read_ptr + sizeof(buf2)-1;fgets(buf2, sizeof(buf2), stdin);puts(buf2);if (feof(stdin))printf("input end/n");return 0;
}

?

  運行上面的程序,輸入多于4個,少于13個字符,并且以連按兩次ctrl+d為結束(不要按回車),從上面的例子,可以看出,每當滿足(_IO_read_end < (_IO_buf_base-_IO_buf_end)) && (_IO_read_ptr == _IO_read_end)時,標準I/O則認為已經到達文件末尾,feof(stdin)才會被設置其中_IO_buf_base-_IO_buf_end是緩沖區的長度。

  也就是說,標準I/O是通過它的緩沖區來判斷流是否要結束了的.這就解釋了為什么即使是一個空文件,標準I/O也需要讀一次,才能使用feof判斷釋放為空。

轉載于:https://www.cnblogs.com/orlion/p/6258691.html

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

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

相關文章

環境變量_配置JAVA環境變量

本文標識 : J00001本文編輯 : YiKi編程工具 : IDEA閱讀時長 : 3分鐘什么是環境變量?環境變量是在操作系統中一個具有特定名字的對象&#xff0c; 它包含了一個或者多個應用程序所將使用到的信息。為什么要配置環境變量?為了方便在控制臺編譯和運行java程序&#xff0c;不…

GotFocus和PreviewLeftButtonDown事件

當TextBox獲得焦點后&#xff0c;其中的文字會被全選。通過GotFocus和PreviewLeftButtonDown事件&#xff0c;就可以模擬上述行為。 如果用戶只是用鍵盤操作&#xff0c;GotFocus事件就足夠了。 如果使用鼠標操作&#xff0c;就要用到2個事件了。TextBox會將光標放在鼠標單擊的…

模式主節點ORACLE DG介紹(物理無實例)

在本文中,我們主要介紹模式主節點的內容,自我感覺有個不錯的建議和大家分享下 DG的三種模式&#xff1a; 硬件以及操縱系統需求&#xff1a; 每日一道理 流逝的日子像一片片凋零的枯葉與花瓣&#xff0c;漸去漸遠的是青春的純情與浪漫。不記得曾有多少雨飄在胸前風響在耳畔&…

分布式消息隊列 Kafka

分布式消息隊列 Kafka 2016-02-25 杜亦舒Kafka是一個高吞吐量的、分布式的消息系統&#xff0c;由Linkedin開發&#xff0c;開發語言為scala具有高吞吐、可擴展、分布式等特點 適用場景 活動數據統計活動數據包括頁面訪問量&#xff08;Page View&#xff09;、被查看內容方面的…

漫游飛行_手機“飛行模式”為何沒被淘汰?內行人坦言:其實是你不會用!

隨著科技的不斷創新&#xff0c;目前市面上出現的手機款式多種多樣&#xff0c;品牌也非常多&#xff0c;有華為、蘋果、三星和小米等等。手機的屏幕也是五花八門&#xff0c;有劉海屏、水滴全面屏等&#xff0c;這些屏幕之間都各有不同。而且手機的更新換代速度很快&#xff0…

multiselect多選下拉框

具體實現 <input type"hidden" id"q_dueDay" name"q_dueDay" value"${baseQueryBean.q_dueDay}">//這個為隱藏域后臺直接使用這個為參數 <select id"example" name"example" multiple"multiple&qu…

序列元素IT面試題——判斷合法出棧序列

本文純屬個人見解&#xff0c;是對前面學習的總結&#xff0c;如有描述不正確的地方還請高手指正~ 在技巧筆試口試上&#xff0c;我們常常會碰到這樣一類題型&#xff0c;如給你一個入棧序列&#xff0c;然后再讓你判斷幾個序列是否有可能為它的出棧序列&#xff0c;如&#xf…

scikit-learn點滴

scikit-learn點滴 scikit-learn是非常漂亮的一個機器學習庫,在某些時候,使用這些庫能夠大量的節省你的時間,至少,我們用Python,應該是很難寫出速度快如斯的代碼的. scikit-learn官方出了一些文檔,但是個人覺得,它的文檔很多東西都沒有講清楚,它說算法原理的時候,只是描述一下,除…

background image

http://www.ajaxblender.com/bgstretcher-2-jquery-stretch-background-plugin-updated.html http://blog.dvxj.com/pandola/jQuery_bgStretcher.html 轉載于:https://www.cnblogs.com/eebb/p/4077231.html

怎樣搭建Android開發平臺(轉)

Android是基于Linux內核的軟件平臺和操作系統&#xff0c;是Google在2007年11月5日公布的手機系統平臺&#xff0c;早期由Google開發&#xff0c;后由開放手機聯盟&#xff08;Open Handset Alliance&#xff09;開發。 它采用了軟件堆層&#xff08;software stack&#xff0c…

mvn deploy 推送到私有倉庫,注意當前日期

由于更改了本機系統時間到過去的一個時間&#xff0c;導致mvn deploy推送到私有倉庫后&#xff0c;該更新的jar包時間戳比較舊&#xff0c;客戶端不能更新得到新的jar包。轉載于:https://www.cnblogs.com/silva/p/6264458.html

我的世界1.7.10java32位_我的世界1.7.10中文版

不知道怎么下載&#xff1f;點我游戲介紹《我的世界1.7.10》中整個世界由各種方塊構成&#xff0c;玩家可以破壞它們&#xff0c;也可以用自己的方塊隨意建造東西。為了在游戲里生存和發展&#xff0c;玩家需要通過伐木、挖礦、捕獵等方式獲取資源&#xff0c;并通過合成系統打…

python程序在函數內執行得更快

http://www.cnblogs.com/nepaul/archive/2012/07/15/2592179.html 為什么Python程序在函數內執行得更快&#xff1f;&#xff08;來源StackOverflow&#xff09; 考慮下面的代碼&#xff0c;一個在函數體內&#xff0c;一個是全局的代碼。 函數內的代碼執行效率為 1.8s 1234def…

USER_EXIT

1、md04的用戶出口 M61X0002 2、me21n/me22n的用戶出口 MM06E005 MBCF0002 3、migo 的用戶出口&#xff1a; MBCF0009 MBCF0002-> EXIT_SAPMM07M_001 4、co11n 的用戶出口&#xff0c;發料不足不允許報工時 EXIT_SAPLCORF_104 查找用戶出口的函數&#xff1a; MODX_FUNCTION…

subject.login(token)是如何確認賬號密碼的_教你如何刪除、關閉、注銷微信小程序...

微信小程序是我們日常生活中經常會接觸到的工具&#xff0c;打開小程序后&#xff0c;它就會留在我們微信的”“發現-小程序”欄。很多人并不知道該如何刪除、關閉小程序&#xff0c;所以今天就跟大家科普下相關問題。1.如何刪除小程序首先&#xff0c;打開微信界面&#xff0c…

上海交通大學2006年數學分析考研試題

轉載于:https://www.cnblogs.com/zhangzujin/p/4078900.html

saltstack 基礎入門文檔

saltstack 和 Puppet Chef 一樣可以讓你同時在多臺服務器上執行命令也包括安裝和配置軟件。Salt 有兩個主要的功能&#xff1a;配置管理和遠程執行。這里講述了saltstack的基本使用方法。 saltstack 簡述 Salt 和 Puppet Chef 一樣可以讓你同時在多臺服務器上執行命令也包括安裝…

出現的是亂碼_cad狀態欄出現了方框亂碼怎么辦?

左下角閱讀原文看CAD視頻好課推薦&#xff1a;1、CAD2014&#xff1a;點擊查看 2、室內&全屋&#xff1a;點擊查看 3、CAD2019&#xff1a;點擊查看4、CAD2018&#xff1a;點擊查看5、Bim教程&#xff1a;點擊查看6、室內手繪&#xff1a;點擊查看7、CAD三維&#xff1a;點…

UILabel 詳解

UILabel 多行文字自動換行 &#xff08;自動折行&#xff09;1.UIView *footerView [[UIView alloc] initWithFrame:CGRectMake(10, 100, 300, 180)]; 2. UILabel *label [[UILabel alloc] initWithFrame:CGRectMake(10, 100, 300, 150)]; 3. label.text "…

mysql創建數據庫指定字符集

mysql 創建 數據庫時指定編碼很重要&#xff0c;很多開發者都使用了默認編碼&#xff0c;但是我使用的經驗來看&#xff0c;制定數據庫的編碼可以很大程度上避免倒入導出帶來的亂碼問題。 我們遵循的標準是&#xff0c;數據庫&#xff0c;表&#xff0c;字段和頁面或文本的編碼…