This is a migrated thread and some comments may be shown as answers.

Context vs Scope and Multithreading philosophy

11 Answers 283 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Gianni Araco
Top achievements
Rank 1
Gianni Araco asked on 12 Sep 2011, 11:13 AM
Good morning.
I'd like to better understand some base philosophy about a couple of things, so I hope you can help me with that.
I have the need to develop software in a heavy multithreading environment with lot of accesses and performance is a must.

First: Context vs Scope.
As far as I have understood, the context is a sort of wrapper for the scope.
It manages transactions implicitly and it offers easier access to the objects directly exposing them.
While with the scope transactions are managed explicitly and objects are accessed through the Extent<> method, thus requiring the knowledge of the objects to use.
Is there anything else worth knowing? Are there indications about scenarios where to use the context or the scope?

Second: Multithreading philosophy.
So far, I tried having a single context to be shared among all the threads, without much success.
Reading here and there, I've seen that it is recommended to have a context for every thread.
Ok, this way it works, but:
1) it seems to me that this way I do not leverage the caching system;
2) if thread A changes some data, I have to refresh the context of thread B. Isn't this a "waste" of resources? As I'll always have to refresh it, being unable to know if/when another thread has modified the data;
3) What is the multithread parameter in the backend for?

Just as a note, so far I haven't been able to make the Refresh work... but I have to make more extensive tests on this.

Thanks.
Gianni Araco

11 Answers, 1 is accepted

Sort by
0
IT-Als
Top achievements
Rank 1
answered on 12 Sep 2011, 12:28 PM
Hi Gianni,

I will try to address your questions:

First:
The Scope is the API used in in the Classic approach of OpenAccess. That is, the classic wizards in visual studio for forward mapping (classes to db) and reverse mapping (db to classes).
The Context is the API used by the Visual Designer and the supported way to do stuff with OpenAccess in the future. Thus, all new development efforts will go into the Context API, where the Scope API will be in "maintenance mode".

However, it is correct that "under the hood" of the Context API the scope API is still living. I guess this is more to the fact that there a few corner functionalities of the Scope API that is not available in the Context API yet.
The recommendation will be to use the Visual Designer and the Context API to create your OpenAccess project. There's also the Fluent API, but it is used to create the meta model in code instead of using the Visual Designer.

Second:
In multi-threaded environments use the "one thread one context" approach. Meaning: Associate the thread with the context (there are several examples of doing so, eg. ContextFactory, etc. in the knowledge base), so that the Context life cycle follows the thread life cycle:

Thread start: Context is created and cached a place where it can be accessed in a thread safe manner during execution of the thread
During thread execution: Get hold of the cached context when needed and perform operations on the API
Thread stop/termination: Context is disposed

With each instance of the Context there's a L(evel) 1 cache, that is, during the life of the Context each loaded object is cached in the L1 cache and each change to a loaded object (or newly created object) is registered. When you commit with SaveChanges() all registered changes in the Context is stored in the DB. When you commit changes registered in the L1 cache are cleaned.

However, the concept of a L2 cache also exists. The difference from the L1 cache is that the L2 cache lives across Context life cycle. So, if you load one object in thread A and load the same object in thread B, thread B gets it from the L2 cache without hitting the database. Even if the Context of thread A has been disposed (thread is terminated).
Moreover the L2 cache can be setup to be clustered (sending so called evictions of cache elements between several nodes) in a server farm.

Pheww.. a lot of words... Hope it shed some light on the questions..

Regards

Henrik


0
Gianni Araco
Top achievements
Rank 1
answered on 12 Sep 2011, 01:12 PM
Hi Henrik,
and thanks for the aswers.

At least two things are clear now:
1) use the context
2) L2 cache is still used by several threads.

And this is great.
Of course, a few more questions arise!

In my window service there's a dozen threads that live as long as the service is running. So I've decided to create several data members, one for each context. Should I use the ContextFactory instead?

Now, when I update some data from thread A do I see it modified in thread B? Or do I have to refresh it?
And does the refresh "rebuilds" the context too or just reloads the data?

I've found OA very useful so far, as it takes easily care of the annoying part about building the data layer, and as you confirm me that L2 cache works across all threads, I see this as an improvement too.
As I mentioned, the service has several threads that poll data every second and updates them depending on several conditions.
And they can work on different aspects of the same data. This forces me to find the most performing solution, as it's a strict requisite.

Best regards,
Gianni Araco
0
IT-Als
Top achievements
Rank 1
answered on 12 Sep 2011, 01:40 PM
Hi again,

I would use a ContextFactory in conjunction with a ContextManager. So, that in the manager you essentially have a thread safe Dictionary of Context instances stored by a specific key...the key could be the thread id (if this is consistent during the lifetime)

So you could get the Context by the id of the current running thread, like (in the thread):

....
OpenAccessContext context = ContextManager.GetContext(threadId);

context.DoSomeStuff();
.....

Regarding updates in two threads: It is correct that if you update in thread A (and it terminates and disposed the context) you will have to load it again unless you are using the L2 cache. Don't worry the Context is a lightweight object to create after the initial instantiation. Upon initial instantiation the meta data for your class model is loaded. This is a heavy process...and only done once (for example at service start up)... on subsequent creation of new contexts the meta data information is used again and again.  So it makes subsequent Context creations relatively lightweight...

regards

Henrik
0
Gianni Araco
Top achievements
Rank 1
answered on 12 Sep 2011, 01:48 PM
Thanks again for the interesting informations.
I will change to ContextManager soon.

Just one clarification.
Thread A and B are started when the service first starts and both die with it, that means that they will be both live for the entire time.

Thread A updates some data and calls for SaveChanges() and goes on with the polling and one second after Thread B checks other conditions on the same data.
Do Thread B sees the updates from Thread A via the L2 cache, or it's better to force a refresh?

Many thanks.
Gianni Araco
0
IT-Als
Top achievements
Rank 1
answered on 12 Sep 2011, 01:51 PM
Hi again,

If you're using the level 2 cache I don't think you need to do a refresh. Since, the L2 cache will take care of when to evict the data from the cache. So, you should be seeing the updated (by thread A) information when you reading it in thread B
0
Accepted
Zoran
Telerik team
answered on 13 Sep 2011, 02:17 PM
Hello Gianni,

When an object is updated by thread A, it is true that it is evicted from the L2 cache. However, if you have that object loaded in thread B, you are not seeing the new data immediately after the evict. 
The objects in OpenAccess are refreshed in two ways and this behavior is valid disregarding if L2 cache is on or off.
  • When a context calls SaveChanges() or ClearChanges(), all the objects that have been loaded by that context are put into a HOLLOW state. This means they will be refreshed next time they are accessed for read/write. The refreshed state is obtained from the L2 cache if the object has not been changed by another thread, otherwise it is fetched the database.
  • If thread B knows about the objects that are changed by thread A(maybe you have some custom logic for that), you can explicitly call Refresh() on the objects that are being changed and get the latest data for them without calling SaveChanges() on the context in thread B. 

And also, thanks a lot to Henrik for explaining the rest of the OpenAccess stack.

 Kind regards,

Zoran
the Telerik team

Thank you for being the most amazing .NET community! Your unfailing support is what helps us charge forward! We'd appreciate your vote for Telerik in this year's SQL Server Community Awards. We are competing in TWO categories and every vote counts! VOTE for Telerik NOW >>

0
IT-Als
Top achievements
Rank 1
answered on 13 Sep 2011, 02:23 PM
Hello Zoran,

You're welcome and thanks for explaining the details of when the object is refreshed automatically (re-fetched) and when it is not. That was actually what I meant, but you said it more precise.

Hope that the answers helped Gianni out..

Regards

Henrik
0
yjh
Top achievements
Rank 1
answered on 14 Sep 2011, 03:24 AM
How about Sqlite ? As we known, it only allows a write operation and multi read operations(If read operations don't conflict with the write operation) at same time.

What is the best practice with using OA on Sqlite ? If keep a shared instance in all Asp.net request,  transactions will work correctly ?
0
Gianni Araco
Top achievements
Rank 1
answered on 14 Sep 2011, 01:55 PM
Many thank to both Henrik and Zoran.
The mechanism is now clear and I have enaugh insight to understand where and when use the different options.

Of course, there's one more question for Henrik: I taken for granted that ContextFactory and ContextManager where two OpenAccess objects, but I can't find any reference to those.
Where you referring to actual objects (in that case in which namespace can I find them) or just to a pattern?

Great support, as expected.

Best regards.
Gianni Araco
0
IT-Als
Top achievements
Rank 1
answered on 15 Sep 2011, 08:59 AM
Hi Gianni,

Sorry... I was referring to the knowledge base article here, which explains the ContextFactory among other things..
0
Zoran
Telerik team
answered on 15 Sep 2011, 03:30 PM
Hi Yao,

The scope/context itself is not a thread-safe object so you should never use single instance for all requests in ASP .NET. The same best practices for scope/context management apply to Sqlite as well as all other database servers. So I still recommend you the Context-Per-Thread approach as pointed by Henrik.

Best wishes,
Zoran
the Telerik team

Thank you for being the most amazing .NET community! Your unfailing support is what helps us charge forward! We'd appreciate your vote for Telerik in this year's SQL Server Community Awards. We are competing in TWO categories and every vote counts! VOTE for Telerik NOW >>

Tags
General Discussions
Asked by
Gianni Araco
Top achievements
Rank 1
Answers by
IT-Als
Top achievements
Rank 1
Gianni Araco
Top achievements
Rank 1
Zoran
Telerik team
yjh
Top achievements
Rank 1
Share this question
or