31 votes

Lequel est le plus rapide ? ByVal ou ByRef ?

En VB.NET, quelle est la plus rapide à utiliser pour les arguments de méthode, ByVal o ByRef ?

En outre, lequel consomme le plus de ressources au moment de l'exécution (RAM) ?


J'ai lu à travers cette question mais les réponses ne sont pas applicables ou suffisamment précises.

100voto

user50612 Points 1921

Les arguments Byval et ByRef doivent être utilisés en fonction des besoins et de la connaissance de leur fonctionnement. pas sur la vitesse.

http://www.developer.com/net/vb/article.php/3669066

En réponse à un commentaire de Slough -

Lequel consomme le plus de ressources au moment de l'exécution ?

Les paramètres sont passés sur la pile. La pile est très rapide, car son allocation de mémoire est simplement un incrément de pointeur pour réserver un nouveau "cadre" ou "enregistrement d'allocation". La plupart des paramètres .NET ne dépassent pas la taille d'un registre machine, de sorte que peu ou pas d'espace "pile" est utilisé pour transmettre les paramètres. En fait, les types de base et les pointeurs sont tous deux alloués sur la pile. La taille de la pile dans .NET est limitée à 1 Mo. Cela devrait vous donner une idée du peu de ressources consommées par le passage des paramètres.

Vous trouverez peut-être cette série d'articles intéressante :

Améliorer les performances grâce à l'allocation de pile (.NET Memory Management : Part 2)

Lequel est le plus rapide ? ByVal ou ByRef.

Il est difficile, au mieux, de mesurer avec précision et de manière équitable - selon le contexte de votre mesure, mais un benchmark que j'ai écrit en appelant une méthode 100 millions de fois a donné le résultat suivant :

  • Type de référence - Passed ByRef : 420 ms
  • Type de référence - Passed ByVal : 382 ms
  • Type de valeur - Passed ByRef : 421 ms
  • Type de valeur - Passed ByVal : 416 ms

    Public Sub Method1(ByRef s As String) Dim c As String = s End Sub

    Public Sub Method2(ByVal s As String) Dim c As String = s End Sub

    Public Sub Method3(ByRef i As Integer) Dim x As Integer = i End Sub

    Public Sub Method4(ByVal i As Integer) Dim x As Integer = i End Sub

    Sub Main()

    Dim s As String = "Hello World!"
    Dim k As Integer = 5
    
    Dim t As New Stopwatch
    
    t.Reset()
    t.Start()
    For i As Integer = 0 To 100000000
        Method1(s)
    Next
    t.Stop()
    
    Console.WriteLine("Reference Type - ByRef " & t.ElapsedMilliseconds)
    
    t.Reset()
    t.Start()
    For i As Integer = 0 To 100000000
        Method2(s)
    Next
    t.Stop()
    
    Console.WriteLine("Reference Type - ByVal " & t.ElapsedMilliseconds)
    
    t.Reset()
    t.Start()
    For i As Integer = 0 To 100000000
        Method3(i)
    Next
    t.Stop()
    
    Console.WriteLine("Value Type - ByRef " & t.ElapsedMilliseconds)
    
    t.Reset()
    t.Start()
    For i As Integer = 0 To 100000000
        Method4(i)
    Next
    t.Stop()
    
    Console.WriteLine("Value Type - ByVal " & t.ElapsedMilliseconds)
    
    Console.ReadKey()

    End Sub

Mettre en commentaire la variable et l'affectation dans chaque méthode -

  • Type de référence - Passed ByRef : 389 ms
  • Type de référence - Passed ByVal : 349 ms
  • Type de valeur - Passed ByRef : 416 ms
  • Type de valeur - Passed ByVal : 385 ms

On pourrait en conclure que le passage des types de référence (chaînes de caractères, classes) ByVal permet de gagner du temps. On pourrait aussi dire que passer les types de valeurs (integer, byte) - ByVal permettra de gagner du temps.

Encore une fois, le temps est négligeable dans le grand schéma des choses. Le plus important est d'utiliser correctement ByVal et ByRef et de comprendre ce qui se passe "en coulisses". Les algorithmes mis en œuvre dans vos routines affecteront très certainement le temps d'exécution de votre programme bien plus encore.

28voto

Jon Skeet Points 692016

Si vous utilisez un très grand type de valeur (Guid est assez grand, par exemple), il peut être très légèrement plus rapide de passer un paramètre par référence. Dans d'autres cas, il peut y avoir más Par exemple, si vous avez un paramètre en octets, un octet est nettement inférieur aux quatre ou huit octets que le pointeur prendrait si vous le transmettiez par référence.

En pratique, vous ne devriez presque jamais vous inquiéter à ce sujet. Écrivez le plus lisible Ce qui signifie presque toujours passer les paramètres par valeur plutôt que par référence. J'utilise très rarement ByRef.

Si vous souhaitez améliorer vos performances et pensez que ByRef vous aidera, s'il vous plaît évaluez-le soigneusement (dans votre situation exacte) avant de vous engager.

EDIT : Je note dans les commentaires d'une autre réponse (précédemment acceptée, maintenant supprimée) qu'il y a beaucoup de malentendus sur ce que signifie ByRef vs ByVal quand il s'agit de types de valeurs. J'ai un article sur le passage des paramètres qui s'est avéré populaire au fil des ans. Il est rédigé en langage C#, mais les mêmes concepts s'appliquent à VB.NET.

11voto

Kibbee Points 36474

Cela dépend. Si vous passez un objet, il s'agit déjà d'un pointeur. C'est pourquoi si vous passez une liste de tableaux (par exemple) et que votre méthode ajoute quelque chose à la liste de tableaux, alors le code appelant a aussi le même objet dans sa liste de tableaux, qui a été passé, parce que c'est la même liste de tableaux. La seule fois où il ne passe pas un pointeur, c'est lorsque vous passez une variable avec un type de données intrinsèque, comme un int, ou un double, dans la fonction. À ce moment-là, elle crée une copie. Toutefois, la taille des données de ces objets est si petite que cela ne fait guère de différence, que ce soit en termes d'utilisation de la mémoire ou de vitesse d'exécution.

5voto

Scott Wisniewski Points 14420

Si vous transmettez un type de référence, ByRef est plus lent.

C'est parce que ce qui est transmis est un pointeur sur un pointeur. Tout accès aux champs de l'objet nécessite le déréférencement d'un pointeur supplémentaire, ce qui prendra quelques cycles d'horloge supplémentaires.

Si vous transmettez un type de valeur, alors byref peut être plus rapide si la structure a de nombreux membres, car il ne transmet qu'un seul pointeur plutôt que de copier les valeurs sur la pile. En termes d'accès aux membres, byref sera plus lent car il doit effectuer une déréférence de pointeur supplémentaire (sp->pValueType->member vs sp->member).

La plupart du temps, en VB, vous ne devriez pas avoir à vous soucier de cela.

Dans .NET, il est rare d'avoir des types de valeurs avec un grand nombre de membres. Ils sont généralement de petite taille. Dans ce cas, la transmission d'un type de valeur n'est pas différente de la transmission de plusieurs arguments à une procédure. Par exemple, si vous aviez un code qui transmettait un objet Point par valeur, sa perforation serait la même que celle d'une méthode qui prendrait les valeurs X et Y comme paramètres. Voir DoSomething(x as integer, y as integer) ne poserait probablement aucun problème de performance. En fait, vous n'y réfléchiriez probablement pas à deux fois.

Si vous définissez vous-même de grands types de valeurs, vous devriez probablement envisager de les transformer en types de référence.

La seule autre différence est l'augmentation du nombre d'indirections de pointeurs nécessaires pour exécuter le code. Il est rare que vous ayez besoin d'optimiser à ce niveau. La plupart du temps, il y a soit des problèmes algorithmiques que vous pouvez résoudre, soit votre goulot d'étranglement est lié aux entrées-sorties, comme l'attente d'une base de données ou l'écriture dans un fichier, auquel cas l'élimination des pointeurs indirects ne vous aidera pas beaucoup.

Ainsi, au lieu de vous concentrer sur la question de savoir si byval ou byref est plus rapide, je vous recommande de vous concentrer sur ce qui vous donne la sémantique dont vous avez besoin. En général, c'est une bonne idée d'utiliser byval, sauf si vous avez spécifiquement besoin de byref. Cela rend le programme beaucoup plus facile à comprendre.

2voto

Artelius Points 25772

Bien que je ne connaisse pas grand-chose aux aspects internes de .NET, je vais parler de ce que je sais des langages compilés. Ce site ne s'applique pas aux types de référence et peut ne pas être tout à fait exact sur les types de valeurs. Si vous ne connaissez pas la différence entre les types de valeur et les types de référence, vous ne devriez pas lire ceci. Je suppose que le système x86 est en 32 bits (avec des pointeurs en 32 bits).

  • Le passage de valeurs inférieures à 32 bits utilise toujours un objet 32 bits sur la pile. Une partie de cet objet sera "inutilisée" ou "de remplissage". Le passage de telles valeurs n'utilise pas moins de mémoire que le passage de valeurs de 32 bits.
  • Le passage de valeurs supérieures à 32 bits utilisera plus d'espace dans la pile qu'un pointeur, et probablement plus de temps de copie.
  • Si un objet est transmis par valeur, le destinataire de l'appel peut aller chercher l'objet dans la pile. Si un objet est transmis par référence, le destinataire doit d'abord récupérer l'adresse de l'objet sur la pile, puis récupérer la valeur de l'objet ailleurs. Par valeur signifie un fetch de moins, non ? En fait, la récupération doit être effectuée par l'appelant - cependant, il se peut que l'appelant ait déjà dû récupérer l'objet pour d'autres raisons, auquel cas une récupération est sauvegardée.
  • Il est évident que toute modification apportée à une valeur par référence doit être sauvegardée en RAM, alors qu'un paramètre par valeur peut être supprimé.
  • Il est préférable de passer par valeur, que de passer par référence pour ensuite copier le paramètre dans une variable locale et ne plus y toucher.

Le verdict :

Il est beaucoup plus important de comprendre ce que ByVal et ByRef font réellement pour vous, et de comprendre la différence entre les types valeur et référence, que de penser aux performances. La règle numéro un est de Utilisez la méthode la plus appropriée à votre code. .

Pour les grands types de valeurs (plus de 64 bits), passez par référence à moins qu'il n'y ait un avantage à passer par valeur (comme un code plus simple, "c'est juste logique", ou la cohérence de l'interface).

Pour les petits types de valeurs, le mécanisme de passage ne fait pas une grande différence en termes de performances, et de toute façon, il est difficile de prédire quelle méthode sera la plus rapide, puisque cela dépend de la taille de l'objet, de la façon dont l'appelant et l'appelé utilisent l'objet, et même des considérations de cache. Faites simplement ce qui est logique pour votre code.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X