Come posso eseguire questo campione di Entity Framework più velocemente

Ho questo codice per aggiungere circa 1500 record al database:

async void button7_Click(object sender, EventArgs e) { var task = await Task.Run(() => { Random rnd = new Random(); for (int i = 0; i <= 1500; i++) { db.Tbls.Add(new Tbl() { Name = "User" + i + 1, Num = rnd.Next(10, i + 10) / 10 }); progress.Report(i * 100 / 1500); } db.SaveChanges(); return db.Tbls.Count(); }); } 

Ma ci sono voluti circa 4 secondi per completare il processo, ma perché ho usato async/await non blocca l’interfaccia utente. Ora la mia domanda è: come posso migliorare questo codice per correre più velocemente. Come posso usare la programmazione parallela qui? Puoi mostrarmi un esempio di come usare TPL?

MODIFICA :

Ho usato il loop parallelo e AddRange come suggerito ma non ha alcun effetto. In tutti i modi suggeriti, il mio processo richiede ancora circa 4 secondi. Apprezzo molto se qualcuno mi può aiutare a risolvere questo problema.

Se la prestazione è l’objective, dovresti usare qualcosa di diverso da EF come dapper (la stessa cosa che StackOverflow.com sta usando) o raw ADO.Net . Oltre a questo, è ansible migliorare le prestazioni di Entity Framework distriggersndo il rilevamento automatico delle modifiche e la convalida al salvataggio :

 yourDbContext.Configuration.AutoDetectChangesEnabled = false; yourDbContext.Configuration.ValidateOnSaveEnabled = false; 

Dovresti combinare il codice precedente con il consiglio di AddRange sull’uso di AddRange .

Un’altra soluzione che potrebbe aiutare ad accelerare i tuoi inserimenti è usando BulkInsert (immagine presa da qui ):

inserisci la descrizione dell'immagine qui

L’elaborazione parallela non sarà di grande aiuto qui, perché il tuo ciclo da solo non richiede affatto tempo. Tutto il tempo consumato si divide in due cose:

  1. Quando si aggiunge un nuovo elemento al contesto di Entity Framework (e si utilizza EF qui come ho capito) – esegue alcune operazioni su molti elementi nel contesto (non solo l’elemento aggiunto) e diventa più lento e lento più elementi aggiunti.

  2. Perfoming 1500 inserimenti di database richiede anche un po ‘di tempo.

La cosa più semplice da fare qui è ridurre il tempo impiegato dal punto 1 nell’elenco precedente. Puoi farlo in questo modo:

 async void button7_Click(object sender, EventArgs e) { var task = await Task.Run(() => { Random rnd = new Random(); var tbls = new List(); for (int i = 0; i <= 1500; i++) { tbls.Add(new Tbl() { Name = "User" + i + 1, Num = rnd.Next(10, i + 10) / 10 }); progress.Report(i * 100 / 1500); } db.Tbls.AddRange(tbls); db.SaveChanges(); return db.Tbls.Count(); }); } 

Usando AddRange e prima raccogliendo tutti gli elementi nella List semplice, AddRange notevolmente il tempo consumato dal tuo codice almeno al di sotto di 1 secondo.

Aggiornare. Se si desidera utilizzare il ciclo parallelo, anche se ciò non è di aiuto, è ansible farlo in questo modo:

 int seed = Environment.TickCount; var random = new ThreadLocal(() => new Random(Interlocked.Increment(ref seed))); var tbls = new ConcurrentBag(); Parallel.For(0, 1500, (i) => { tbls.Add(new Tbl() { Name = "User" + i + 1, Num = random.Value.Next(10, i + 10) / 10 }); }); db.Tbls.AddRange(tbls); 

Cose da notare:

  • Random non è thread-safe, quindi utilizziamo le istanze locali del thread (una per ogni thread all'interno del loop parallelo), ognuna con un valore di seed diverso.
  • List non è thread-safe: usiamo invece ConcurrentBag .