[C#] Object cloning

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • maniak
  • Registratie: Augustus 2000
  • Laatst online: 08-07 13:45
Ik heb een cache gemaakt van een hoop objecten vanwege de traagheid van het onderliggende systeem. Dit heb ik gedaan dmv een List<voorbeeld>, dit werkt goed.
Dit geeft wel een probleem, namelijk dat ik de objecten moet clonen voordat ik ze "doorgeef". Dit heb ik gedaan door het volgende te doen (zie code onderaan).

Dit gaat prima, maar kost wel wat tijd en aangezien soms wel tot 1000 objecten doorlopen moeten worden gaat het ineens om een paar seconden. De applicatie is een webapplicatie en ik heb liever niet dat gebruikers een paar seconden moeten wachten.

Nu kan ik ICloneable gebruiken maar ik ben er niet zeker van dat de List<int> ook gecloned wordt (deepcloning).

Heeft iemand een oplossing om het eea te versnellen?

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public static class GenericCopier<T>
{
     public static T DeepCopy(object objectToCopy)
     {
        using (MemoryStream memoryStream = new MemoryStream())
        {
           BinaryFormatter binaryFormatter = new BinaryFormatter();
           binaryFormatter.Serialize(memoryStream, objectToCopy);
           memoryStream.Seek(0, SeekOrigin.Begin);
           return (T) binaryFormatter.Deserialize(memoryStream);
        }
     }


}

public class voorbeeld : ISerializable
{
    public int Id {get; internal set;}
    public List<int> Koppelingen{get; internal set;}
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
         string serializeString = "";
         serializeString += Framework.FastSerializer.Serialize(Id);
         serializeString += (char)255 + Framework.FastSerializer.Serialize(Koppelingen);
         info.AddValue("serializeString", serializeString, typeof(string));
     }
     public voorbeeld (SerializationInfo info, StreamingContext context)
     {
         string serializeString = (string)info.GetValue("serializeString", typeof(string));
         string[] values = serializeString.Split((char) 255);
         Id = (int?)Framework.FastSerializer.DeSerialize(values[0]);
         Koppelingen = new List<int>();
         Koppelingen .AddRange((List<int>) Framework.FastSerializer.DeSerialize(values[1]));
     }
}

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
maniak schreef op maandag 24 september 2012 @ 10:20:
Dit gaat prima, maar kost wel wat tijd en aangezien soms wel tot 1000 objecten doorlopen moeten worden gaat het ineens om een paar seconden.
Waarom gebruik je dan ook een List<T> en niet gewoon een Dictionary of Hashtable of HashSet? Met een list moet je elke keer de hele list doorlopen om te vinden wat je wil hebben (O(n)), met een dictionary/hashtable/hashset heb je meteen 't element dat je wil hebben (O(1)).

C#/.NET Fundamentals: Choosing the Right Collection Class
maniak schreef op maandag 24 september 2012 @ 10:20:
Nu kan ik ICloneable gebruiken maar ik ben er niet zeker van dat de List<int> ook gecloned wordt (deepcloning).
Als je een List<int> wil clonen kun je gewoon een nieuwe list instantiëren en de constructor de originele list passen. Zie daarvoor deze overloaded constructor.

Verder: meten == weten. Als je iets niet zeker weet meet je 't gewoon (dat kan dmv. een simpele Stopwatch of wat geavanceerder met een profiler). En als je niet zeker weet of iets wel/niet ge(deep)cloned wordt probeer je het toch gewoon :?

Wat ik in deze gevallen vaak/meestal doe is een copy constructor maken. Als je een beetje consequent kunt werken werkt dat prima en veel beter/sneller dan serializen en ander kunst-en-vliegwerk. ICloneable implementeren heeft sowieso zo z'n nadelen.

[ Voor 39% gewijzigd door RobIII op 24-09-2012 11:47 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 15:40
Waarom moet je clonen ?

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 16:30

.oisyn

Moderator Devschuur®

Demotivational Speaker

Omdat ie de data van de objecten cachet, ipv de objecten zelf wat natuurlijk veel logischer is om te doen.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • maniak
  • Registratie: Augustus 2000
  • Laatst online: 08-07 13:45
De reden waarom het zo opgelost is is tijd.. als enige ontwikkelaar en een bepaalde tijdsdruk heb ik niet de luxe om alles te doen zoals voorgeschreven, dan kies je soms voor een snellere oplossing.

Daarbij zie ik nog niet echt een probleem (of verschil) om een object te cachen met values.. uiteindelijk is alles een object of ik nu een DataTable gebruik of een List. Daarbij zijn Lists makkelijk in combinatie met Linq en kan ik alles strong typed houden.

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
maniak schreef op maandag 24 september 2012 @ 12:50:
Daarbij zijn Lists makkelijk in combinatie met Linq en kan ik alles strong typed houden.
Dictionaries etc. werken ook prima met Linq en zijn net zo strong-typed (de hashtable overigens niet). En ik zie echt geen reden om een list te kiezen. Een cache is bijna per definitie een key/value store en dus heb je veel meer aan een dictionary dan een list. Los van de manier waarop je 'm benaderd (en 't bijkomende performance gewin) kun je die net zo goed (en nog steeds) i.c.m. Linq gebruiken.

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • maniak
  • Registratie: Augustus 2000
  • Laatst online: 08-07 13:45
RobIII schreef op maandag 24 september 2012 @ 13:02:
[...]

Dictionaries etc. werken ook prima met Linq en zijn net zo strong-typed (de hashtable overigens niet). En ik zie echt geen reden om een list te kiezen. Een cache is bijna per definitie een key/value store en dus heb je veel meer aan een dictionary dan een list. Los van de manier waarop je 'm benaderd (en 't bijkomende performance gewin) kun je die net zo goed (en nog steeds) i.c.m. Linq gebruiken.
Je hebt gelijk.. maar goed.. de topic ging over het clonen van objecten en niet zozeer over mijn gekozen oplossing ;)

Na wat proberen denk ik aan de volgende oplossing:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    public class voorbeeld
    {
        public int id { get; set; }

        public List<string> strings { get; set; } 
        public List<int> listId { get; set; } 
        
        public voorbeeld(int a, List<int> b, List<string> c)
        {
            id = a;
            listId = new List<int>(b);
            strings = new List<string>(c);
        }

        public object Clone()
        {
            voorbeeld V = (voorbeeld)this.MemberwiseClone();
            V.strings = new List<string>(strings);
            V.listId = new List<int>(listId);
            return V;
        }
    }


Dit lijkt te werken en is wss een stuk sneller dan wat ik nu doe.

Acties:
  • 0 Henk 'm!

  • HMS
  • Registratie: Januari 2004
  • Laatst online: 07-07 21:06

HMS

Aangezien dit in een web omgeving is heb je neem ik aan ook aan concurrency gedacht?

Ik zou een ConcurrentDictionary gebruiken als cache storage.

Acties:
  • 0 Henk 'm!

  • alwinuzz
  • Registratie: April 2008
  • Laatst online: 10:13
Of gewoon de ingebouwde ASP.net cache?

En ik snap niet waarom je de objecten moet clonen als je ze in de cache stopt?

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
HMS schreef op maandag 24 september 2012 @ 14:51:
Aangezien dit in een web omgeving is heb je neem ik aan ook aan concurrency gedacht?

Ik zou een ConcurrentDictionary gebruiken als cache storage.
Dat is natuurlijk ook afhankelijk van de scope/lifetime van de cache.

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 08-07 14:14
maniak schreef op maandag 24 september 2012 @ 12:50:
De reden waarom het zo opgelost is is tijd.. als enige ontwikkelaar en een bepaalde tijdsdruk heb ik niet de luxe om alles te doen zoals voorgeschreven, dan kies je soms voor een snellere oplossing.
Je bent nu een erg omslachtige oplossing aan het bouwen die je later alsnog moet refactoren. Zoals Oisyn aangeeft: als je gewoon de objecten cached heb je dat gekloon hoogstwaarschijnlijk niet nodig.

https://niels.nu


Acties:
  • 0 Henk 'm!

  • doskabouter
  • Registratie: Oktober 2004
  • Laatst online: 07-07 16:31
Natuurlijk moet je een deep-clone teruggeven uit je cache.

Wat als bv de aanroepende kant met je objecten gaat rommelen, dan wil je niet dat de objecten die in de cache staan aangepast worden

Edit: door schade & schande wijs geworden :)

Edit2: het zou mooi zijn als je een object als read-only zou kunnen markeren

[ Voor 24% gewijzigd door doskabouter op 24-09-2012 21:16 ]

Het grote voordeel van windows is dat je meer dos-boxen kan openen


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 15:40
Serializen om te clonen vind ik nog altijd een eenvoudige & goede (onderhoudbare) manier.
Als je performance probleem echt daar zit, dan zou je eens kunnen kijken naar andere serializatie-frameworks. (protocol-buffers bv).

https://fgheysels.github.io/

Pagina: 1