I have been playing with Async/parallel execution in entity framework for while. I'm not sure if I'm doing it right.
I have two entity contexts: one for reading and one for writing. The reading context has more than 200000 rows in table Customer
. It took 9 minutes on my PC (i7+8GB).
let FindGender(skip : int, take : int) : Async<unit> =
async {
try
use readContext = new ReadContext()
use context = new WriteContext()
let! customers = Async.AwaitTask
<| readContext.Customers.OrderBy(fun c -> c.CustomerId).Skip(skip).Take(take)
.ToListAsync()
let findGender (c : NA.Data.Entities.Customer) : unit =
let name = context.Names.FirstOrDefault(fun i -> i.Name.ToLower() = c.FirstName.ToLower())
match name = Unchecked.defaultof<NameTable> with
| false ->
Console.WriteLine(String.Format("{0}", name.Name))
// create customer
let customer = new Customer()
customer.ExternalCustomerId <- c.CustomerId
customer.ExternalCustomerName <- c.FirstName
customer.GenderId <- name.Gender
customer.GenderName <- name.GenderType.ToString()
customer.NameListId <- name.NameId
context.Customers.Add(customer) |> ignore
| _ -> 0 |> ignore
customers |> Seq.iter findGender
let! _ = Async.AwaitTask <| context.SaveChangesAsync()
return()
with ex -> printfn "Exception handled. %A" ex
}
let sw = new Stopwatch()
sw.Start()
let customerCount = 218114
let step = 1000
[ 0..step..customerCount ]
|> Seq.map (fun i ->
if i + step < customerCount then (i, step)
else (i, customerCount - i))
|> Seq.map (fun (step, take) -> FindGender(step, take))
|> Async.Parallel
|> Async.RunSynchronously
|> ignore
sw.Stop()
printfn "%A" sw.Elapsed
.AsNoTracking()
to both of the contexts, I believe, to avoid needless caching and associated cache trashing. I don't see a reason to use nested contexts either and it may be quite beneficial to performance to un-nest them. \$\endgroup\$