【问题标题】:Why Realm throwing Realm accessed from incorrect thread, when the whole operation is executed on the same Thread当整个操作在同一个线程上执行时,为什么领域会抛出从错误线程访问的领域
【发布时间】:2020-09-29 22:12:32
【问题描述】:
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.Showcases 中的Showcase 展示)行正在引发异常。同样,在 if 条件 !string.Equals(previousResponse, response.Data) 中,如果我将 previousResponse 作为 existingShowcase.SerializedResponse 访问,而不是局部变量,则会引发一些异常。根据文档,我们不应该跨线程传递对象,但在这种情况下,所有操作都在同一个线程中。

【问题讨论】:

    标签: c# .net xamarin.forms realm realm-mobile-platform


    【解决方案1】:

    在这种情况下,所有操作都在同一个线程中。

    不,实际上不是。这是因为await 的工作原理。

    When await acts asynchronously, it captures its current context - SynchronizationContext.CurrentTaskScheduler.Current。在这种情况下,上下文是线程池上下文。因此,当方法在await 之后恢复执行时,它可能会在任何线程池线程上恢复执行。

    【讨论】:

      【解决方案2】:

      正如斯蒂芬在他的回答中所说,await 不会继续返回到原始调用线程,除非原始线程上有 SychronizationContext。当使用Task.RunTask.Factory.StartNew 时,工作线程默认没有SychronizationContextNito.AsyncEx 包(实际上是由 Stephen 编写的)提供了 AsyncContext 类,它可以在 Task.RunTask.Factory.StartNew 委托中使用,任何 Tasks 在传递的委托中 awaited除非使用 .ConfigureAwait(false),否则 to AsyncContext.Run 将在同一线程上继续。

      https://github.com/StephenCleary/AsyncEx/blob/master/doc/AsyncContext.md

      为了在 Realm 的上下文中使这更容易,我创建了一个简单的扩展方法来允许对 Realm 数据库执行异步后台线程工作:

      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);
      }));
      

      在我的应用程序中,我通常在某个地方有 UI 线程的 Realm 实例的句柄,所以如果我需要做昂贵的后台工作,我只需使用 whateverRealm.RunTask(async backgroundRealm =&gt; /* some work with awaits in it */。传递给委托的backgroundRealm 参数将可以安全地在委托内的任何位置使用,只要在awaited 的任何任务上都没有调用.ConfigureAwait(false)

      【讨论】:

        猜你喜欢
        • 2017-09-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-13
        • 2017-03-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多