web-dev-qa-db-fra.com

L'utilisation de scanf () dans les programmes C ++ est plus rapide que d'utiliser cin?

Je ne sais pas si cela est vrai, mais lorsque je lisais FAQ sur l'un des sites fournissant des problèmes, j'ai trouvé quelque chose qui a attiré mon attention:

Vérifiez vos méthodes d'entrée/sortie. En C++, l'utilisation de cin and cout est trop lente. Utilisez-les et vous garantissez de ne pouvoir résoudre aucun problème avec une quantité d’entrée ou de sortie décente. Utilisez plutôt printf et scanf.

Quelqu'un peut-il s'il vous plaît clarifier cela? L'utilisation de scanf () dans les programmes C++ est-elle plus rapide que d'utiliser cin >> quelque chose? Si oui, est-ce une bonne pratique de l'utiliser dans les programmes C++? Je pensais que c'était spécifique au C, bien que j'apprenne juste le C++ ...

109
zeroDivisible

Voici un test rapide d'un cas simple: un programme pour lire une liste de nombres à partir d'une entrée standard et XOR tous les nombres.

version d'iostream:

#include <iostream>

int main(int argc, char **argv) {

  int parity = 0;
  int x;

  while (std::cin >> x)
    parity ^= x;
  std::cout << parity << std::endl;

  return 0;
}

version de scanf:

#include <stdio.h>

int main(int argc, char **argv) {

  int parity = 0;
  int x;

  while (1 == scanf("%d", &x))
    parity ^= x;
  printf("%d\n", parity);

  return 0;
}

Résultats

À l'aide d'un troisième programme, j'ai généré un fichier texte contenant 33 280 276 nombres aléatoires. Les temps d'exécution sont:

iostream version:  24.3 seconds
scanf version:      6.4 seconds

La modification des paramètres d'optimisation du compilateur ne semble pas avoir beaucoup modifié les résultats.

Donc: il y a vraiment une différence de vitesse.


EDIT: clyfish indique ci-dessous que la différence de vitesse est due en grande partie au maintien de la synchronisation des fonctions iostream I/O avec les fonctions C I/O. Nous pouvons le désactiver en appelant std::ios::sync_with_stdio(false);:

#include <iostream>

int main(int argc, char **argv) {

  int parity = 0;
  int x;

  std::ios::sync_with_stdio(false);

  while (std::cin >> x)
    parity ^= x;
  std::cout << parity << std::endl;

  return 0;
}

Nouveaux résultats:

iostream version:                       21.9 seconds
scanf version:                           6.8 seconds
iostream with sync_with_stdio(false):    5.5 seconds

C++ iostream gagne! Il s’avère que cette synchronisation/vidage interne est ce qui ralentit normalement iostream i/o. Si nous ne mélangeons pas stdio et iostream, nous pouvons l'éteindre et iostream est le plus rapide.

Le code: https://Gist.github.com/3845568

197
nibot

http://www.quora.com/Is-cin-cout-slower-than-scanf-printf/answer/Aditya-Vishwakarma

Les performances de cin/cout peuvent être lentes car elles doivent rester synchronisées avec la bibliothèque C sous-jacente. Ceci est essentiel si C IO et C++ IO vont être utilisés).

Cependant, si vous n'utilisez que C++ IO, utilisez simplement la ligne ci-dessous avant toute opération IO.

std::ios::sync_with_stdio(false);

Pour plus d'informations à ce sujet, consultez le libstdc ++ docs correspondant.

61
clyfish

Scanf est probablement un peu plus rapide que l’utilisation de flux. Bien que les flux fournissent beaucoup de sécurité de type et ne nécessitent pas d'analyse de chaînes de format au moment de l'exécution, ils présentent généralement l'avantage de ne pas nécessiter d'allocations de mémoire excessives (cela dépend de votre compilateur et de votre environnement d'exécution). Cela dit, à moins que la performance ne soit votre seul objectif final et que vous soyez dans le chemin critique, vous devriez vraiment privilégier les méthodes plus sûres (plus lentes).

Herb Sutter " Les formateurs de chaîne de Manor Farm " écrit un article très délicieux qui décrit en détail les performances des formateurs de chaîne tels que sscanf et lexical_cast et quel genre de choses les faisait courir lentement ou rapidement. C'est un peu analogue, probablement au genre de choses qui affecterait les performances entre le style C IO et le style C++. La principale différence avec les formateurs a tendance à être le type de sécurité et le nombre de mémoire allocations.

42
1800 INFORMATION

Je viens de passer une soirée à travailler sur un problème sur UVa Online (Factovisors, un problème très intéressant, regardez-le):

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=35&page=show_problem&problem=108

Je devenais TLE (délai dépassé) sur mes soumissions. Sur ces sites de juges en ligne chargés de la résolution de problèmes, vous disposez d’un délai de 2 à 3 secondes pour traiter potentiellement des milliers de tests utilisés pour évaluer votre solution. Pour les problèmes de calcul intensifs comme celui-ci, chaque microseconde compte.

J'utilisais l'algorithme suggéré (à lire sur les forums de discussion du site), mais j'obtenais toujours des TLE.

J'ai simplement changé "cin >> n >> m" en "scanf ("% d% d ", & n, & m)" et les quelques minuscules "couts" en "printfs", et mon TLE est devenu "Accepted"!

Alors, oui, cela peut faire une grande différence, surtout lorsque les délais sont courts.

16
Bogatyr

Si vous vous souciez de la performance et du formatage des chaînes, jetez un œil à la bibliothèque Matthew Wilson's FastFormat .

edit - lien vers la publication d'accu sur cette bibliothèque: http://accu.org/index.php/journals/1539

6
xtofl

Oui, iostream est plus lent que cstdio.
Oui, vous ne devriez probablement pas utiliser cstdio si vous développez en C++.
Cela étant dit, il existe des moyens encore plus rapides d'obtenir des E/S que scanf si vous ne vous souciez pas du formatage, saisissez safety, blah, blah, blah ...

Par exemple, ceci est une routine personnalisée pour obtenir un numéro de STDIN:

inline int get_number()
{
    int c;        
    int n = 0;

    while ((c = getchar_unlocked()) >= '0' && c <= '9')
    {
        // n = 10 * n + (c - '0');
        n = (n << 3) + ( n << 1 ) + c - '0';
    }
    return n;
}
2
pedro.lupin

Il existe des implémentations stdio ( libio ) qui implémentent FILE * en tant que streambuf C++ et fprintf en tant qu'analyseur de format d'exécution. Les IOstream n'ont pas besoin d'analyse de format d'exécution, tout est fait à la compilation. Ainsi, avec les serveurs partagés, il est raisonnable de s’attendre à ce que iostreams soit plus rapide au moment de l’exécution.

2
MSalters

Le problème est que cin nécessite beaucoup de temps système car il vous donne une couche d’abstraction supérieure à scanf(). Vous ne devriez pas utiliser scanf() sur cin si vous écrivez un logiciel C++, car c’est ce que vous voulez cin est pour. Si vous voulez des performances, vous n'écririez probablement pas d'entrées/sorties en C++ de toute façon.

1
dreamlax

Les instructions cin et cout généralement utilisées semblent être plus lentes que scanf et printf en C++, mais elles sont en réalité PLUS RAPIDES!

Le problème est le suivant: en C++, chaque fois que vous utilisez cin et cout, un processus de synchronisation a lieu par défaut et garantit que si vous utilisez à la fois scanf et cin dans votre programme, ils travaillent alors en synchronisation. Ce processus de synchronisation prend du temps. Par conséquent, cin et cout apparaissent comme étant plus lents.

Toutefois, si le processus de synchronisation est configuré pour ne pas se produire, cin est plus rapide que scanf.

Pour ignorer le processus de synchronisation, incluez l'extrait de code suivant dans votre programme dès le début de main():

std::ios::sync_with_stdio(false);

Visitez ce site pour plus d'informations.

0
Prasoon Varshney
#include <stdio.h>
#include <unistd.h>

#define likely(x)       __builtin_expect(!!(x), 1)
#define unlikely(x)     __builtin_expect(!!(x), 0)

static int scanuint(unsigned int* x)
{
  char c;
  *x = 0;

  do
  {
      c = getchar_unlocked();
      if (unlikely(c==EOF)) return 1;
  } while(c<'0' || c>'9');

  do
  {
      //*x = (*x<<3)+(*x<<1) + c - '0';
      *x = 10 * (*x) + c - '0';
      c = getchar_unlocked();
      if (unlikely(c==EOF)) return 1;
  } while ((c>='0' && c<='9'));

  return 0;
}

int main(int argc, char **argv) {

  int parity = 0;
  unsigned int x;

  while (1 != (scanuint(&x))) {
    parity ^= x;
  }
  parity ^=x;
  printf("%d\n", parity);

  return 0;
}

Il y a un bogue à la fin du fichier, mais ce code C est considérablement plus rapide que la version C++ plus rapide.

paradox@scorpion 3845568-78602a3f95902f3f3ac63b6beecaa9719e28a6d6 ▶ make test        
time ./xor-c < Rand.txt
360589110

real    0m11,336s
user    0m11,157s
sys 0m0,179s
time ./xor2-c < Rand.txt
360589110

real    0m2,104s
user    0m1,959s
sys 0m0,144s
time ./xor-cpp < Rand.txt
360589110

real    0m29,948s
user    0m29,809s
sys 0m0,140s
time ./xor-cpp-noflush < Rand.txt
360589110

real    0m7,604s
user    0m7,480s
sys 0m0,123s

Le C++ original a pris 30 secondes, le code C a pris 2 secondes.

0
hexec