3
\$\begingroup\$

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
\$\endgroup\$
5
  • 1
    \$\begingroup\$ What has the profiler shown? .. \$\endgroup\$ – Vasily Kirichenko Mar 7 '15 at 12:49
  • \$\begingroup\$ a) Does your code work as you expect and b) what are you trying to ask us to do? To increase the speed of your code? \$\endgroup\$ – Dan Mar 7 '15 at 13:42
  • \$\begingroup\$ Yes it does work as expected, I tried to ask if I use good approach to use async with entity framework, and parallel execution. \$\endgroup\$ – Martin Bodocky Mar 7 '15 at 14:14
  • \$\begingroup\$ You could add .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\$ – Veksi Mar 8 '15 at 5:31
  • 2
    \$\begingroup\$ Upon looking at the code more closely, you are iterating over the database, which will be slow. I suspect this is the main source of slowness. You should make only one query to names using the customers you have. If they are in the same database, you could just join them and get back the result you want. A database view could further increase speed, make it easier to query, make the system more "strongly typed" and name your query to make it easier to debug on DB, make it easier for the DB to maintain plan cache etc. If the goal is to load data, bulk loading may suit better (with bigger data \$\endgroup\$ – Veksi Mar 8 '15 at 6:52
1
\$\begingroup\$
match name = Unchecked.defaultof<NameTable> with
| false -> …
| _ -> …

If you're checking whether a condition is true, you should use if, not pattern matching. It's simpler and clearer.


0 |> ignore

Instead of this, you can write the unit value: ().

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.