【问题标题】:Eloquent model observer performance雄辩的模型观察者表现
【发布时间】:2023-03-07 01:43:01
【问题描述】:

如果我有多个模型并且我处理大量事件,那么在我的 AppServiceProvider 中我会为我的模型创建一个观察者,例如:

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        User::observe(UserObserver::class);
        User2::observe(UserObserver2::class);
        User3::observe(UserObserver3::class);
        User4::observe(UserObserver4::class);
        User5::observe(UserObserver5::class);
        User6::observe(UserObserver6::class);
        User7::observe(UserObserver7::class);
        User8::observe(UserObserver8::class);
        User9::observe(UserObserver9::class);
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

它会造成一些性能损失吗?如果我对每个应用程序访问都正确理解了observe method,它将循环遍历我所有的模型观察者方法并将它们与雄辩的事件相匹配,所以如果我有 30 个模型观察者,它会导致性能不佳吗?

是否有一些巧妙的方法可以仅在模型使用时声明观察类?所以不是在每个应用程序访问中声明观察者,即使在不需要时,每个模型只会在使用时才知道它的观察者?

【问题讨论】:

  • 不确定,你的做法可能很独特。如果您将 Laravel 中的事件用于它们的用途,我认为不会存在性能问题。是的,它们都将被启动,但是当您需要其中一个事件时,它们会被潜在地启动并激活。覆盖它们实际上可能会减慢速度。与路由一样,将最常用的事件放在顶部可能很有用,最不可能的事件放在底部。不确定这是否会有所作为,但您可以尝试一下。

标签: laravel laravel-5 eloquent laravel-5.4 laravel-eloquent


【解决方案1】:

特别是对于模型观察者,它对性能的影响比典型的事件注册要大。额外的开销来自 Laravel 如何处理观察者事件映射。由于正在注册的事件是基于现有方法的,Laravel最少每个观察者对method_exists 进行 13 次调用。

对于几个观察者来说,这没什么大不了的。但是,如果您开始使用观察者进行审计跟踪流程并涉及多个模型,则此成本可能会开始增加。

例如,我曾经开发过一个应用程序,它有四个通用观察者,它们观察了大约 300 个模型(其中一些模型由观察者共享)。这变成了超过 600 个 Model::observe 调用,因此超过 7,800 个调用到 method_exists

我实际上已经创建了一个包 (reedware/laravel-events) 来解决这个问题。相反,您可以通过配置文件注册观察者(和其他事件),并且可以缓存这些事件。缓存机制实际上也适用于观察者(这不适用于开箱即用的 Laravel),因此观察者的成本变得非常低。

或者,您可以放弃观察者设计模式,并在可引导特征中使用 Model::creating(...) 挂钩,或者只是抛出自定义事件并为它们注册侦听器。

【讨论】:

  • 感谢 method_exists 确实是我的意图,您是否尝试将事件缓存放入核心?听起来像谷歌解决方案
【解决方案2】:

如果你在 Laravel 中使用事件,事件将在每个请求上注册(但不会触发)。

更准确地说,事件将被注册意味着User::observe(UserObserver::class);loop through all methodsUserObserver 并将它们保存在User 类的调度程序的数组中。只有通过User模型的update/create方法被执行,注册的UserObserver方法才会被触发,即从调度器调用。

因此,如果您在 Observer 类中有 30 个模型,每个模型有 5 个方法,那么每个对调度程序的请求都会有 150 个数组绑定。但是,观察者的方法不会在每个请求期间被调用,只有在事件触发时才会调用。因此,与加载 120kb 徽标或执行查询调用所需的时间相比,我认为 150 个数组分配不会对请求时间产生影响。

最好的办法当然是自己衡量。在绑定观察者和不绑定观察者的情况下测量请求的时间。你可以使用debugbar


旁注:使用deferred providers 不会有任何区别,因为您必须将观察者调用放入提供者的boot 方法中。来自文档:

如果您的提供者在服务容器中注册绑定,您可以选择推迟其注册,直到实际需要其中一个已注册的绑定。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-22
    • 1970-01-01
    • 2021-08-11
    • 1970-01-01
    • 2011-12-21
    • 1970-01-01
    相关资源
    最近更新 更多