如何使用 $http.get 有效地轮询 mySQL 数据库

Posted

技术标签:

【中文标题】如何使用 $http.get 有效地轮询 mySQL 数据库【英文标题】:How to efficiently poll mySQL database with $http.get 【发布时间】:2018-05-14 20:28:06 【问题描述】:

** 角度 1.X ** 大家好!我需要帮助来使这个 $http.get 函数异步,正如您从代码中看到的那样,我当前的临时解决方案是 setInterval 的 displayData 范围。这显然不是一个有效的解决方案,因为它占用了太多的 CPU、太多的用户数据并且可能导致 UI 上的一些闪烁。我希望在更新数据库时更新数组。 请不要推荐我切换到其他框架。 谢谢

$scope.displayData = function() 
    $http.get("read.php").success(function(data) 
        $scope.links = data;
    );

setInterval(function()$scope.displayData();, 500);

这是我的 PHP ("read.php")

  <?php
  include("../php/connect.php");
  session_start();
  $output = array();
  $team_id = $_SESSION['team_id'];
  $sql  = "SELECT record_id, user_id, link, note, timestamp FROM             
  link_bank WHERE team_id = '$team_id' AND status = 'valid'";
  $result = mysqli_query($connect, $sql);
  if (mysqli_num_rows($result) > 0) 
        while ($row = mysqli_fetch_array($result)) 
        $output[] = $row;        
  
  echo json_encode($output);
  
  ?> 

【问题讨论】:

考虑采用使用套接字的推送通知策略。见How to integrate nodeJS + Socket.IO and PHP? 另见Real time chat, message handling - Socket.io, PHP, MySQL, Apache。 【参考方案1】:

$http.get 已经异步了!异步函数就是在未来某个未知时间结束运行的任何函数。

您真正想要做的是long polling。这是您定期向服务器发送请求以获取最新数据的地方,这不是一个好主意有几个原因(包括您所说的闪烁和高 CPU 使用率)。

我知道您说过您不希望任何人推荐其他框架,但是尝试编写自己的框架以在数据库更新时通知客户端是一项艰巨的任务。我们无法提供任何简短的 sn-p 代码来为您提供 PHP 和 javascript 的功能。

但是,您可以尝试使用 WebSockets 滚动您自己的代码。这是以您建议的方式进行服务器到客户端通信的最直接、非框架的方式。

【讨论】:

我所说的其他框架的意思是建议我放弃 angular 1.x 和/或 php 并重新开始使用新框架。我不介意添加我已经拥有的东西。 好的,太好了。查看用于 PHP 的 Ratchet (socketo.me)。这应该让你开始。 @AbdulAmoud PHP 是一种语言,JS 是一种语言,Angular 是一个框架,只是为了澄清。此外,您轮询的方式非常低效,特别是如果网络延迟最终接近您的 500 毫秒间隔。另一个问题是您正在使用 $http 自动触发摘要,并且您每次都替换数组,无论是否发生更改。如果您发送上次更改的时间并在响应中指出数据是否已更改,则“闪烁”会少得多。使用 chrome 分析和时间线工具。 我怀疑以更有效的方式获取数据是否会变得太重要,目前客户端代码的编写方式似乎主要是问题,它只需要优化。 我在看socket.io网站,好像只关注node.js。【参考方案2】:

检查调试工具的一些细节,有大量的网络请求需要很长时间并且没有返回任何新数据。

使用时间线记录来获取客户端处理的一些细节。

在我看到的视图中,客户端并没有受到太大影响,但没有数据很难真正评估。

您可以查看时间线,然后放大记录数据的一部分,查看实际调用了哪些函数以及它们花费了多长时间。还有一些很好的扩展来检查角度中的 $watchers

https://chrome.google.com/webstore/detail/angular-watchers/nlmjblobloedpmkmmckeehnbfalnjnjk?hl=en

如果绑定只更新一次(在 ng-repeats 多次有用),您可以使用 ::bindOnce 语法来减少观察者。这有助于减少消化时间,因为需要检查更改的观察者更少。如果您有很长的元素列表(1000 多个),那么使用某种虚拟滚动条或分页 UI 组件有助于避免在 DOM 中每行元素生成 1000 个*元素。

在服务器端,您可以使用 xdebug 插件/模块从服务器端收集分析数据,并可以使用 kcachegrind 评估该数据以查找服务器花费最多时间的位置,但也可以使用某种服务器侧缓存和更智能的逻辑,以避免在没有任何变化的情况下不断访问数据库(也许考虑使用 Redis 或查看 memcached 以加快这些服务器端的速度,或者看看它是否只是网络延迟)。

更改语言或框架而不实际分析以获取关于究竟是什么是慢的数据并不是一个伟大的举措,IMO 只会在新的热点之间来回跳跃,而不了解为什么或是否重要。

下面的示例是来自 PHP 脚本的相对较快的响应。它基本上什么都不做,只是吐出一个硬编码的 JSON 响应,使用 Redis 或 memcached 不会有太多额外的开销来获取响应,尤其是空响应。

【讨论】:

感谢您的详细回答,但我真的希望改变服务的执行方式。 @AbdulAmoud 答案是视情况而定,您需要收集更多数据来确定真正慢的地方。我留下了一些关于常见问题/解决方案的建议,但没有灵丹妙药。 除了偶尔的闪烁之外,没有什么真的很慢。我没有得到任何差评。但是有一件事,如果您创建一个条目并尝试选择它,以便您可以复制它,则在用户有机会复制之前选择消失了,这是因为条目基本上消失并替换了自己。现在这实际上很好,但我的目标是创建可能被成千上万人使用的应用程序,而这肯定不会。 500ms 得到一个空响应是相当慢的 我的服务器给出一个相当直接的响应需要大约 50ms 如果你期望事情在给定的时间窗口内发生那么你需要考虑慢那个窗口。对于客户端上的脚本执行,每帧执行超过 16 毫秒意味着帧长于每秒 1/60,这意味着您没有获得 60fps,时间是相对的。关于“闪烁”,如果您在数据未更改时不替换元素,则不会遇到此问题。 另外关于“闪烁”,如果您可以重现您在 jsfiddle 或 plnkr 中看到的问题或可以戳到的某个地方,那么我可以尝试解决具体问题,但同样没有灵丹妙药取决于你在做什么

以上是关于如何使用 $http.get 有效地轮询 mySQL 数据库的主要内容,如果未能解决你的问题,请参考以下文章

如何在不轮询的情况下监视页面的更改?

ThreadPoolExecutor 挂起

实现web消息推送的技术和采用长轮询corundumstudio介绍

股市数据馈送如何工作?

在Java中尾随/轮询日志文件的最有效方法[重复]

子进程的异步等待方式