Task.Factory.StartNew(async () =>
{
try
{
ShowCaseInfo existingShowcase = DBService.GetDB().FetchShowcaseInfo();
string previousResponse = existingShowcase?.SerializedResponse;
Response response = await CloudService.GetCloudService().FetchShowcase();
if (response.Status == ResponseStatus.SUCCESS && !string.Equals(previousResponse, response.Data))
{
ShowCaseInfo showcaseInfo = JsonConvert.DeserializeObject<ShowCaseInfo>(response.Data, _settings);
showcaseInfo.SerializedResponse = response.Data;
DBService.GetDB().InsertOrUpdateShowcase(showcaseInfo);
FetchShowcaseProducts(showcaseInfo.Showcases);
}
else
{
List<Showcase> emptyCases = new List<Showcase>();
if (existingShowcase != null)
{
foreach (Showcase showcase in existingShowcase.Showcases)
{
if (showcase.Products.Count == 0)
{
emptyCases.Add(showcase);
}
}
}
FetchShowcaseProducts(emptyCases);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
});
foreach (Showcase showcase in existingShowcase.Showcases) line is throwing the exception. Similarly, in the if condition.string,Equals(previousResponse. response,Data). instead of a local variable had I accessed the previousResponse as existingShowcase,SerializedResponse. some exception was thrown, As per the doc, we are not supposed to pass the object across threads. but in this case all the operations are within the same thread.
in this case all the operations are within the same thread.
No, they're actually not. This is because of how await
works.
When await
acts asynchronously, it captures its current context - either SynchronizationContext.Current
or TaskScheduler.Current
. In this case, the context is the thread pool context. So, when the method resumes executing after the await
, it may resume executing on any thread pool thread.
As Stephen said in his answer, await
will not return to the original calling thread in its continuation unless there is a SychronizationContext
on the original thread. When using Task.Run
or Task.Factory.StartNew
, the worker thread won't have a SychronizationContext
by default. The Nito.AsyncEx
package (which is actually written by Stephen) provides the AsyncContext
class which can be used inside a Task.Run
or Task.Factory.StartNew
delegate, and any Task
s which are await
ed inside the delegate passed to AsyncContext.Run
will continue on the same thread unless .ConfigureAwait(false)
is used.
https://github.com/StephenCleary/AsyncEx/blob/master/doc/AsyncContext.md
To make this easier in the context of Realm, I created a simple extension method to allow asynchronous background-thread work to be done to a Realm database:
public static Task RunTask(this Realm realm, Func<Realm, Task> workFunction) => Task.Run(() => AsyncContext.Run(async () => {
using var workerRealm = await Realm.GetInstanceAsync(realm.Config);
await workFunction(workerRealm);
}));
public static Task<TResult> RunTask<TResult>(this Realm realm, Func<Realm, Task<TResult>> workFunction) => Task.Run(() => AsyncContext.Run(async () => {
using var workerRealm = await Realm.GetInstanceAsync(realm.Config);
return await workFunction(workerRealm);
}));
In my app I usually have a handle to the UI thread's Realm instance somewhere, so if I ever need to do expensive background work, I just use whateverRealm.RunTask(async backgroundRealm => /* some work with awaits in it */
. The backgroundRealm
parameter passed into the delegate will be safe to use anywhere inside the delegate so long as .ConfigureAwait(false)
is not called on any tasks being await
ed.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.