带有 AsyncWorker 的 Electron Node 插件挂在 macOS 上的 `dispatch_group_wait` 上

发布于 2025-01-10 22:38:53 字数 851 浏览 0 评论 0原文

我正在创建一个 Node 插件来从 macOS 照片库导出视频文件,因为这需要几秒钟,我将代码包装到 AsyncWorker 中。

C++ / Objective-C 代码:

class Napi_PhotosExport_AsyncWorker : public Napi::AsyncWorker
{

  void Execute()
  {
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_enter(group);

    [[PHImageManager defaultManager] requestExportSessionForVideo:... {

      // this should be called, but never be called.
      dispatch_group_leave(group);
    }];

    // this blocks the current thread and wait for the above callback.
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
  }

};

上面的代码在我的 macOS Cocoa 应用程序中工作,但由于某种原因在 Electron / Node 环境中不起作用。我预计可以在某个时刻调用dispatch_group_leave,以便dispatch_group_wait正确返回而不是阻塞线程。

我正在寻求 macOS 和 Electron 开发人员的帮助。也许 Grand Central Dispatcher 不应该在 Node 插件中使用,而我需要使用 C++ 锁?

I am creating a Node addon to export a video file from macOS Photos library, as it takes a few seconds, I wrapped the code into an AsyncWorker.

The C++ / Objective-C code:

class Napi_PhotosExport_AsyncWorker : public Napi::AsyncWorker
{

  void Execute()
  {
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_enter(group);

    [[PHImageManager defaultManager] requestExportSessionForVideo:... {

      // this should be called, but never be called.
      dispatch_group_leave(group);
    }];

    // this blocks the current thread and wait for the above callback.
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
  }

};

The code above works in my macOS Cocoa application, but it doesn't work in Electron / Node environment for some reason. I expected the dispatch_group_leave can be called at some point, so that dispatch_group_wait returns properly instead of blocking the thread.

I am looking for some help from both macOS and Electron developers. Maybe Grand Central Dispatcher should not be used in Node addon, and I need to use C++ lock instead?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小鸟爱天空丶 2025-01-17 22:38:53

我们总是建议不要使用这种模式的原因是:

  • 如果闭包被分派回当前正在等待的同一线程,则可能会发生死锁;

  • 如果你有线程爆炸(无论是在这里还是埋在项目的其他地方),这种模式也可能会死锁;和

  • 这只是一种低效的反模式,即使不引入死锁,也会不必要地占用线程。

通常,您永远不应该让异步方法绑定线程以使它们同步运行。使用异步模式;不要与他们战斗。


顺便说一句,这个问题几乎肯定与您使用调度组无关。信号量或锁也会导致同样的问题。问题不在于你如何阻塞线程,而在于你根本阻塞了它。


如果您这样做是为了管理异步任务之间的依赖关系,传统的解决方案包括从异步 NSOperation 自定义子类到第三方 Promise/Futures 库。在 Swift 中,我们也会将合并和异步等待并发模式放入讨论中,但我假设这两个都不适合您。不用说,您可以采用传统的、不太优雅的模式来解决这个问题,例如递归(在完成前一个任务的同时启动下一个任务)或嵌套完成处理程序(诚然,这可能会变得笨拙)。

The reason we always advise against this pattern is that:

  • if the closure is dispatched back to the same thread that is currently waiting, that can deadlock;

  • if you have thread explosion (either here or buried elsewhere in your project), this pattern can also deadlock; and

  • it is simply an inefficient anti-pattern that unnecessarily ties up threads, even if you do not introduce deadlocks.

As a rule, you simply never should be making asynchronous methods tie up threads to make them behave synchronously. Use asynchronous patterns; do not fight them.


BTW, the problem is almost certainly unrelated to the fact that you are using a dispatch group. Semaphores or locks are going to result in the same problem. The problem isn't how you're blocking the thread, but the fact that you are blocking it at all.


If you are doing this so that you can manage dependencies between asynchronous tasks, traditional solutions range from asynchronous NSOperation custom subclass, to third-party promises/futures library. In Swift, we would throw Combine and the async-await concurrency patterns into the discussion, too, but I'm assuming neither of those is an option for you. Needless to say, you could adopt traditional, less elegant patterns to solve this problem, such as recursion (initiating the next task in the completion of the prior one) or nested completion handlers (which, admittedly, can become unwieldy).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文