2013-04-22 3 views
-4

Почему syscall read() работает медленнее, чем функция getc()?Почему read() работает медленнее, чем getc()

for (;;) { 
     chr++; 
     amr=read(file1, &wc1, 1); 
     amr2=read(file2, &wc2, 1); 
     if (wc1 == wc2) { 
      if (wc1 == '\n') 
       line++; 
      if (amr == 0) { 
       if (eflg) 
        return (1); 
       return (0); 
      } 
      continue; 
     } 

медленнее, чем

for (;;) { 
    chr++; 
    c1 = getc(file1); 
    c2 = getc(file2); 
    if (c1 == c2) { 
     if (c1 == '\n') 
      line++; 
     if (c1 == EOF) { 
      if (eflg) 
       return (1); 
      return (0); 
     } 
     continue; 
    } 

когда ЕОКП() вызова он использует чтения() системный вызов, так почему медленнее?

+2

Как вы определили, что это медленнее? –

+10

[двойной] (http: //unix.stackexchange.com/questions/73264/why-read-is-slower-than-getc) –

+3

Поскольку не буферизация – BLUEPIXY

ответ

13

read() включает контекстный переключатель в ядро, которое относительно медленное. Когда вы используете его напрямую и читаете по одному байту за раз, у вас много переключателей контекста. Но когда вы используете getc(), он будет вызывать read() один раз для 4 или 8 кБ и возвращать символы из этого без дополнительных контекстных переключателей, пока он не исчерпает буфер.

Если вы используете read() с большим буфером, это будет быстрее, чем getc(), потому что общая буферизация стандартной библиотеки C имеет некоторые накладные расходы.

(Изменить) Обратите внимание, что эти диски могут быть прочитаны только в блоках, которые составляют 512 байт для всех обычно используемых носителей. Так что в любом случае должна быть некоторая буферизация в ядре. И поскольку память выделяется на страницах 4096 байт, большинство систем (конечно, Linux) читают, по крайней мере, столько, сколько с каждым запросом на физическое хранилище. Но контекстный переключатель также дорог, поэтому дополнительный уровень буферизации в пользовательской области по-прежнему экономит много времени. Эта буферизация используется во всем libc IO, который включает все, используя FILE* (буфер является частью структуры FILE), поэтому fread() будет быстрее, чем read() для небольших чтений.

2

Ответ # 1: Это не медленнее.

Ответ # 2: Это зависит.

Для каждого байта, который вы читаете из файла, вы не хотите делать syscall (который включает контекстный переключатель в системах с защитой памяти). Вы, при первом доступе по размеру байта, читаете соответствующий объем данных (скажем, 4k) в память и обслуживаете первый байт вызывающему. При последующих чтениях размера байта вам не нужно вызывать ядро ​​или вообще обращаться к файлу; вы просто передаете следующий байт из буфера, пока не будете читать другой блок 4k.

Это то, что стандартные вызовы библиотеки C (fread(), fgetc(), fgets() и т. Д.) Делают по умолчанию. Вы можете проверить BUFSIZ, чтобы получить размер буфера по умолчанию. Вы можете изменить размер буфера или вообще отключить буферизацию с помощью вызова setvbuf().

read() не входит в стандартную библиотеку C, это системный вызов POSIX. В основном, это backend для стандартных вызовов библиотеки C в системах POSIX. (В системе Windows fgetc() вместо этого вызывается Win32 API.) Таким образом, read() не буферизует, а вызов его для блоков размером с байтом неэффективен. Если вы звоните read(), вы обычно делаете это, потому что хотите сделать буферизацию самостоятельно.

Вообще говоря, не следует смешивать вызовы ввода-вывода POSIX и стандартной библиотеки. Используйте POSIX API для доступа на низкоуровневом уровне, используйте стандартную библиотеку для удобства переносов (и хорошую производительность по умолчанию).

Смежные вопросы