前言说明

在文中《【学习笔记】开源库之 - sigslot (提供该库存在对象拷贝崩溃问题的解决方案)》已经介绍过 sigslot ,此文主要应用在实际的工作项目中时,发现会有拦截信号的需求,而原生的 sigslot 不支持拦截。因此增加 sigslot 拦截特性,便于适应这种需求。

应用场景

在很多需要联网的项目中,很多功能模块都必不可免的会产生依赖关系,如联网后需要进行网络时间同步、连接服务器等操作。而网络时间同步和连接服务器的操作需要网络畅通时才能进行,而连接服务器需要在网络时间同步成功后才能进行(假设连接服务器需要以正确的时间计算连接秘钥),因此可能会出现以下几种情况:

  • 情况一,如设备只连接了路由器,而路由器却没有连接互联网,这时候进行网络时间同步和连接服务器等操作就会非常耗时,且注定不会成功。
  • 情况二,已经连接了互联网,但是网络时间同步失败,连接服务器又需要当前准确的时间来计算秘钥,这时候连接服务器的操作就会失败。

以WIFI联网方式为例,根据 sigslot 的设计,信号通知槽函数的顺序与连接信号的顺序一致,因此我们可以将WIFI连接成功的信号,连接到三个不同模块的槽函数,第一个是网络处理的模块,负责进一步验证是否已经连接到互联网,第二个是时间同步模块,负责同步网络时间,第三个是服务器模块,负责与服务器进行通信。那么当网络连接成功的信号发出,会按照顺序先触发网络状态模块、再触发时间同步模块,最后触发服务器模块。

收到网络连接成功的事件后,在网络处理模块中,如果无法访问外网,则可以发出提示音提醒用户网络未连接到互联网,借此提升用户体验,然后返回非零值,让 sigslot 停止触发下一个槽函数,如果可以访问外网,就返回零值,继续触发下一个槽函数,即时间同步模块。在时间同步模块中,如果同步时间失败,也是返回非零值,如果同步成功则返回零值,继续触发下一个槽函数,即服务器模块,服务器模块就可以真正畅通无阻的进行与服务器进行连接等相关操作了。

实现方式

要实现如上的设计,需要改造 siglsot ,主要进行如下两步即可:

  • 修改槽函数的返回值类型,由 void 改为 int
  • 修改触发信号的接口 .emit() 、operator()
    • 对每个槽函数的返回值进行判断,非零值则跳出。
    • 返回值由 void 改为 int ,如果槽函数返回值非零,则直接返回该值,否则返回零值。

以上的修改,可以实现,不同的槽函数返回不同的值,这样触发信号的函数就可以通过返回值得知是哪个槽函数拦截了。

以下为 signal0<> 的修改方法:

  1. --- C:\sigslot.h 2020-05-09 00:34:55.000000000 +0800
  2. +++ F:\sigslot.h 2020-05-09 01:41:50.000000000 +0800
  3. @@ -315,13 +315,13 @@
  4. template<class mt_policy>
  5. class _connection_base0
  6. {
  7. public:
  8. virtual ~_connection_base0() {}
  9. virtual has_slots_interface* getdest() const = 0;
  10. - virtual void emit() = 0;
  11. + virtual int emit() = 0;
  12. virtual _connection_base0* clone() = 0;
  13. virtual _connection_base0* duplicate(has_slots_interface* pnewdest) = 0;
  14. };
  15. template<class arg1_type, class mt_policy>
  16. class _connection_base1
  17. @@ -1779,13 +1779,13 @@
  18. _connection0()
  19. {
  20. m_pobject = NULL;
  21. m_pmemfun = NULL;
  22. }
  23. - _connection0(dest_type* pobject, void (dest_type::* pmemfun)())
  24. + _connection0(dest_type* pobject, int (dest_type::* pmemfun)())
  25. {
  26. m_pobject = pobject;
  27. m_pmemfun = pmemfun;
  28. }
  29. virtual ~_connection0()
  30. @@ -1799,25 +1799,25 @@
  31. virtual _connection_base0<mt_policy>* duplicate(has_slots_interface* pnewdest)
  32. {
  33. return new _connection0<dest_type, mt_policy>((dest_type*)pnewdest, m_pmemfun);
  34. }
  35. - virtual void emit()
  36. + virtual int emit()
  37. {
  38. - (m_pobject->*m_pmemfun)();
  39. + return (m_pobject->*m_pmemfun)();
  40. }
  41. virtual has_slots_interface* getdest() const
  42. {
  43. return m_pobject;
  44. }
  45. private:
  46. dest_type* m_pobject;
  47. - void (dest_type::* m_pmemfun)();
  48. + int (dest_type::* m_pmemfun)();
  49. };
  50. template<class dest_type, class arg1_type, class mt_policy>
  51. class _connection1 : public _connection_base1<arg1_type, mt_policy>
  52. {
  53. public:
  54. @@ -2239,53 +2239,63 @@
  55. : _signal_base0<mt_policy>(s)
  56. {
  57. ;
  58. }
  59. template<class desttype>
  60. - void connect(desttype* pclass, void (desttype::* pmemfun)())
  61. + void connect(desttype* pclass, int (desttype::* pmemfun)())
  62. {
  63. lock_block<mt_policy> lock(this);
  64. _connection0<desttype, mt_policy>* conn =
  65. new _connection0<desttype, mt_policy>(pclass, pmemfun);
  66. m_connected_slots.push_back(conn);
  67. pclass->signal_connect(this);
  68. }
  69. - void emit()
  70. + int emit()
  71. {
  72. lock_block<mt_policy> lock(this);
  73. typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
  74. typename connections_list::const_iterator itEnd = m_connected_slots.end();
  75. + int nResult = 0;
  76. while (it != itEnd)
  77. {
  78. itNext = it;
  79. ++itNext;
  80. - (*it)->emit();
  81. + if (nResult = (*it)->emit()) {
  82. + return nResult;
  83. + }
  84. it = itNext;
  85. }
  86. +
  87. + return 0;
  88. }
  89. - void operator()()
  90. + int operator()()
  91. {
  92. lock_block<mt_policy> lock(this);
  93. typename connections_list::const_iterator itNext, it = m_connected_slots.begin();
  94. typename connections_list::const_iterator itEnd = m_connected_slots.end();
  95. + int nResult = 0;
  96. while (it != itEnd)
  97. {
  98. itNext = it;
  99. ++itNext;
  100. - (*it)->emit();
  101. + if (nResult = (*it)->emit()) {
  102. + return nResult;
  103. + }
  104. it = itNext;
  105. }
  106. +
  107. + return 0;
  108. }
  109. // add lmx: https://me.csdn.net/lovemengx -- 2020-04-12
  110. signal0 &operator=(const signal0 &singnal)
  111. {
  112. if (this != &singnal)

测试例程

  1. #include <iostream>
  2. #include <thread>
  3. #include "sigslot.h"
  4. using namespace std;
  5. using namespace sigslot;
  6. #define iprintf(format,...) printf("[inf] %s ->%s():%05d "format" <--\n", typeid(this).name(), __func__, __LINE__, ##__VA_ARGS__)
  7. class SignalSource
  8. {
  9. public:
  10. signal0<> TriSignal0;
  11. signal1<string> TriSignal1;
  12. signal2<string, int> TriSignal2;
  13. signal3<string, int, int> TriSignal3;
  14. signal4<string, int, int, int> TriSignal4;
  15. signal5<string, int, int, int, int> TriSignal5;
  16. signal6<string, int, int, int, int, int> TriSignal6;
  17. signal7<string, int, int, int, int, int, int> TriSignal7;
  18. signal8<string, int, int, int, int, int, int, int> TriSignal8;
  19. public:
  20. void run()
  21. {
  22. iprintf("TriSigna0 Reslut:%d\n", TriSignal0());
  23. this_thread::sleep_for(chrono::seconds(1));
  24. iprintf("TriSignal Reslut:%d\n", TriSignal1("TriSignal1"));
  25. this_thread::sleep_for(chrono::seconds(1));
  26. iprintf("TriSigna2 Reslut:%d\n", TriSignal2("TriSignal2", 0));
  27. this_thread::sleep_for(chrono::seconds(1));
  28. iprintf("TriSigna3 Reslut:%d\n", TriSignal3("TriSignal3", 0, 1));
  29. this_thread::sleep_for(chrono::seconds(1));
  30. iprintf("TriSigna4 Reslut:%d\n", TriSignal4("TriSignal4", 0, 1, 2));
  31. this_thread::sleep_for(chrono::seconds(1));
  32. iprintf("TriSigna5 Reslut:%d\n", TriSignal5("TriSignal5", 0, 1, 2, 3));
  33. this_thread::sleep_for(chrono::seconds(1));
  34. iprintf("TriSigna6 Reslut:%d\n", TriSignal6("TriSignal6", 0, 1, 2, 3, 4));
  35. this_thread::sleep_for(chrono::seconds(1));
  36. iprintf("TriSigna7 Reslut:%d\n", TriSignal7("TriSignal7", 0, 1, 2, 3, 4, 5));
  37. this_thread::sleep_for(chrono::seconds(1));
  38. iprintf("TriSigna8 Reslut:%d\n", TriSignal8("TriSignal8", 0, 1, 2, 3, 4, 5, 6));
  39. this_thread::sleep_for(chrono::seconds(1));
  40. }
  41. };
  42. class SignalProcessBase : public has_slots<>
  43. {
  44. public:
  45. virtual int onSignal0() { return 0; };
  46. virtual int onSignal1(string) { return 0; };
  47. virtual int onSignal2(string, int) { return 0; };
  48. virtual int onSignal3(string, int, int) { return 0; };
  49. virtual int onSignal4(string, int, int, int) { return 0; };
  50. virtual int onSignal5(string, int, int, int, int) { return 0; };
  51. virtual int onSignal6(string, int, int, int, int, int) { return 0; };
  52. virtual int onSignal7(string, int, int, int, int, int, int) { return 0; };
  53. virtual int onSignal8(string, int, int, int, int, int, int, int) { return 0; };
  54. };
  55. class SignalProcess1 : public SignalProcessBase
  56. {
  57. private:
  58. virtual int onSignal0() { iprintf(""); return 0; };
  59. virtual int onSignal1(string) { iprintf(""); return 1; }; // 拦截, 返回1
  60. virtual int onSignal2(string, int) { iprintf(""); return 0; };
  61. virtual int onSignal3(string, int, int) { iprintf(""); return 0; };
  62. virtual int onSignal4(string, int, int, int) { iprintf(""); return 0; };
  63. virtual int onSignal5(string, int, int, int, int) { iprintf(""); return 0; };
  64. virtual int onSignal6(string, int, int, int, int, int) { iprintf(""); return 0; };
  65. virtual int onSignal7(string, int, int, int, int, int, int) { iprintf(""); return 0; };
  66. virtual int onSignal8(string, int, int, int, int, int, int, int) { iprintf(""); return 0; };
  67. };
  68. class SignalProcess2 : public SignalProcessBase
  69. {
  70. private:
  71. virtual int onSignal0() { iprintf(""); return 0; };
  72. virtual int onSignal1(string) { iprintf(""); return 0; };
  73. virtual int onSignal2(string, int) { iprintf(""); return 2; }; // 拦截,返回2
  74. virtual int onSignal3(string, int, int) { iprintf(""); return 0; };
  75. virtual int onSignal4(string, int, int, int) { iprintf(""); return 0; };
  76. virtual int onSignal5(string, int, int, int, int) { iprintf(""); return 0; };
  77. virtual int onSignal6(string, int, int, int, int, int) { iprintf(""); return 0; };
  78. virtual int onSignal7(string, int, int, int, int, int, int) { iprintf(""); return 0; };
  79. virtual int onSignal8(string, int, int, int, int, int, int, int) { iprintf(""); return 0; };
  80. };
  81. class SignalProcess3 : public SignalProcessBase
  82. {
  83. private:
  84. virtual int onSignal0() { iprintf(""); return 0; };
  85. virtual int onSignal1(string) { iprintf(""); return 0; };
  86. virtual int onSignal2(string, int) { iprintf(""); return 0; };
  87. virtual int onSignal3(string, int, int) { iprintf(""); return 3; }; // 拦截,返回3
  88. virtual int onSignal4(string, int, int, int) { iprintf(""); return 0; };
  89. virtual int onSignal5(string, int, int, int, int) { iprintf(""); return 0; };
  90. virtual int onSignal6(string, int, int, int, int, int) { iprintf(""); return 0; };
  91. virtual int onSignal7(string, int, int, int, int, int, int) { iprintf(""); return 0; };
  92. virtual int onSignal8(string, int, int, int, int, int, int, int) { iprintf(""); return 0; };
  93. };
  94. class SignalManager : public SignalProcessBase
  95. {
  96. private:
  97. virtual int onSignal0() { iprintf(""); return 9; }; // 拦截, 返回9
  98. virtual int onSignal1(string) { iprintf(""); return 0; };
  99. virtual int onSignal2(string, int) { iprintf(""); return 0; };
  100. virtual int onSignal3(string, int, int) { iprintf(""); return 0; };
  101. virtual int onSignal4(string, int, int, int) { iprintf(""); return 0; };
  102. virtual int onSignal5(string, int, int, int, int) { iprintf(""); return 0; };
  103. virtual int onSignal6(string, int, int, int, int, int) { iprintf(""); return 0; };
  104. virtual int onSignal7(string, int, int, int, int, int, int) { iprintf(""); return 0; };
  105. virtual int onSignal8(string, int, int, int, int, int, int, int) { iprintf(""); return 0; };
  106. private:
  107. SignalProcess1 mSignalProcess1;
  108. SignalProcess2 mSignalProcess2;
  109. SignalProcess3 mSignalProcess3;
  110. void connectBase(SignalSource* pSignalSource, SignalProcessBase* pSignalProcessBase)
  111. {
  112. pSignalSource->TriSignal0.connect(pSignalProcessBase, &SignalProcessBase::onSignal0);
  113. pSignalSource->TriSignal1.connect(pSignalProcessBase, &SignalProcessBase::onSignal1);
  114. pSignalSource->TriSignal2.connect(pSignalProcessBase, &SignalProcessBase::onSignal2);
  115. pSignalSource->TriSignal3.connect(pSignalProcessBase, &SignalProcessBase::onSignal3);
  116. pSignalSource->TriSignal4.connect(pSignalProcessBase, &SignalProcessBase::onSignal4);
  117. pSignalSource->TriSignal5.connect(pSignalProcessBase, &SignalProcessBase::onSignal5);
  118. pSignalSource->TriSignal6.connect(pSignalProcessBase, &SignalProcessBase::onSignal6);
  119. pSignalSource->TriSignal7.connect(pSignalProcessBase, &SignalProcessBase::onSignal7);
  120. pSignalSource->TriSignal8.connect(pSignalProcessBase, &SignalProcessBase::onSignal8);
  121. }
  122. public:
  123. void connect(SignalSource *pSignalSource)
  124. {
  125. connectBase(pSignalSource, (SignalProcessBase*)this);
  126. connectBase(pSignalSource, (SignalProcessBase*)&mSignalProcess1);
  127. connectBase(pSignalSource, (SignalProcessBase*)&mSignalProcess2);
  128. connectBase(pSignalSource, (SignalProcessBase*)&mSignalProcess3);
  129. }
  130. };
  131. int main()
  132. {
  133. SignalSource mSignalSource;
  134. SignalManager mSignalManager;
  135. mSignalManager.connect(&mSignalSource);
  136. mSignalSource.run();
  137. return 0;
  138. }

测试结果

可以观察触发信号的返回值,即可确认所有槽函数是否都正常执行,如果某个槽函数返回非零值,即表明有拦截且可以通过返回值即可得知是哪个槽函数拦截的。

如 TirSignal0 , 被第一个槽函数 SignalManager::onSignal0() 拦截(观察返回值为9),那么之后的SignalProcess1::onSignal0()、SignalProcess2::onSignal0()、SignalProcess3::onSignal0() 槽函数都不会被执行。

完整修改文件:https://download.csdn.net/download/lovemengx/12406152

温故知新

在分析代码的时候发现槽函数有重新实现拷贝构造函数:

  1. template<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
  2. class has_slots : public has_slots_interface, public mt_policy
  3. {
  4. private:
  5. ......
  6. public:
  7. ......
  8. has_slots(const has_slots& hs)
  9. {
  10. lock_block<mt_policy> lock(this);
  11. const_iterator it = hs.m_senders.begin();
  12. const_iterator itEnd = hs.m_senders.end();
  13. while (it != itEnd)
  14. {
  15. (*it)->slot_duplicate(&hs, this);
  16. m_senders.insert(*it);
  17. ++it;
  18. }
  19. }
  20. ......
  21. private:
  22. ......
  23. };

这就意味着在,可以通过传入已经有信号和槽的连接关系的对象,来初始化新的对象,使新的对象具有相同的连接关系。这个功能很有用,特别合适在多个不通过的功能模块需要共享相同的多个信号场景,当第一个功能模块已经建立好所有的信号与槽的连接关系,那么其他的功能模块可以使用此模块来构造,即可完成连接关系的拷贝,当需要新增加信号或者移除信号的时候,只需要修改第一个模块的连接关系,即可同步其他模块的信号连接关系。需要注意的是,需要将槽函数抽象为父类,其他模块继承该类才能实现不同功能模块的连接关系同步,可以参考本文的例程。如果是相同的类不同的对象则可以直接使用。

下面的代码通过构造函数,减少了信号连接的操作,也可以实现和上面例程相同的效果。(请忽略下面内存释放问题o(∩_∩)o)

  1. ---
  2. +++
  3. @@ -122,15 +122,15 @@
  4. virtual int onSignal7(string, int, int, int, int, int, int) { iprintf(""); return 0; };
  5. virtual int onSignal8(string, int, int, int, int, int, int, int) { iprintf(""); return 0; };
  6. private:
  7. - SignalProcess1 mSignalProcess1;
  8. - SignalProcess2 mSignalProcess2;
  9. - SignalProcess3 mSignalProcess3;
  10. + //SignalProcess1 mSignalProcess1;
  11. + //SignalProcess2 mSignalProcess2;
  12. + //SignalProcess3 mSignalProcess3;
  13. void connectBase(SignalSource* pSignalSource, SignalProcessBase* pSignalProcessBase)
  14. {
  15. pSignalSource->TriSignal0.connect(pSignalProcessBase, &SignalProcessBase::onSignal0);
  16. pSignalSource->TriSignal1.connect(pSignalProcessBase, &SignalProcessBase::onSignal1);
  17. pSignalSource->TriSignal2.connect(pSignalProcessBase, &SignalProcessBase::onSignal2);
  18. @@ -144,16 +144,21 @@
  19. public:
  20. void connect(SignalSource *pSignalSource)
  21. {
  22. +
  23. connectBase(pSignalSource, (SignalProcessBase*)this);
  24. - connectBase(pSignalSource, (SignalProcessBase*)&mSignalProcess1);
  25. - connectBase(pSignalSource, (SignalProcessBase*)&mSignalProcess2);
  26. - connectBase(pSignalSource, (SignalProcessBase*)&mSignalProcess3);
  27. + //connectBase(pSignalSource, (SignalProcessBase*)&mSignalProcess1);
  28. + //connectBase(pSignalSource, (SignalProcessBase*)&mSignalProcess2);
  29. + //connectBase(pSignalSource, (SignalProcessBase*)&mSignalProcess3);
  30. +
  31. + SignalProcess1* pSignalProcess1 = new SignalProcess1(*(SignalProcess1*)this);
  32. + SignalProcess2* pSignalProcess2 = new SignalProcess2(*(SignalProcess2*)pSignalProcess1);
  33. + SignalProcess3* pSignalProcess3 = new SignalProcess3(*(SignalProcess3*)pSignalProcess2);
  34. }
  35. };
  36. int main()
  37. {

【学习笔记】开源库之 - sigslot (在解决浅拷贝问题的基础上增加信号拦截功能)的更多相关文章

  1. Linux学习笔记(7)CRT实现windows与linux的文件上传下载

    Linux学习笔记(7)CRT实现windows与linux的文件上传下载 按下Alt + p 进入SFTP模式,或者右击选项卡进入 命令介绍 help 显示该FTP提供所有的命令 lcd 改变本地上 ...

  2. [Golang学习笔记] 03 库源码文件

    库源码文件:不能被直接运行的源码文件,它仅用于存放程序实体,这些程序实体可以被其他代码使用. 代码包声明的基本规则: 1. 同目录下的源码文件的代码包声明语句要一致.也就是说,它们要同属于一个代码包( ...

  3. [原创]java WEB学习笔记34:Session 案例 之 解决表单重复提交

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  4. Dynamic CRM 2013学习笔记(十一)利用Javascript实现子表合计(汇总,求和)功能

    我们经常有这样一种需求,子表里新加或修改一数值后,要马上在主表里把它们的和显示在主表上.如果用插件来实现,可以实现求和,但页面上还要刷新一下才能显示正确.这时就考虑到用JS来实现这一功能,并自动刷新页 ...

  5. MySQL学习笔记:一道group by+group_concat解决的小问题

    闲来无事,逛逛V2EX发现一道MySQL数据库题目,原题如下: 遂打开很长一段时间都没用过SQLyog,噗呲噗呲的干起活来…… 建测试表: CREATE TABLE test_001 ( id INT ...

  6. Docker技术入门与实战 第二版-学习笔记-6-仓库

    仓库(Repository)是集中存放镜像的地方 一个容易混淆的概念是注册服务器(Registry). 实际上注册服务器是管理仓库的具体服务器,每个服务器上可以有多个仓库,而每个仓库下面有多个镜像. ...

  7. mysql学习笔记1---mysql ERROR 1045 (28000): 错误解决办法(续:深入分析)

    在命令行输入mysql -u root –p,输入密码,或通过工具连接数据库时,经常出现下面的错误信息,详细该错误信息很多人在使用MySQL时都遇到过. ERROR 1045 (28000): Acc ...

  8. 【小梅哥SOPC学习笔记】SOPC开发常见问题及解决办法集锦

    SOPC开发常见问题及解决办法集锦 一.Symbol 'NULL' could not be resolved 近期在评估使用NIOS II处理器进行项目的开发,我使用的软件是Quartus II 1 ...

  9. SharpGL学习笔记(十二) 光源例子:解决光源场景中的常见问题

    笔者学到光源这一节,遇到的问题就比较多了,收集了一些如下所述: (1) 导入的3ds模型,如果没有材质光照效果很奇怪.如下图 (2) 导入的3ds模型,有材质,灯光效果发暗,材质偏色,效果也很奇怪. ...

  10. poco网络库分析,教你如何学习使用开源库

    Poco::Net库中有 FTPClient HTML HTTP HTTPClient HTTPServer ICMP Logging Mail Messages NetCore NTP OAuth ...

随机推荐

  1. python中的if条件语句

    # 如果...就... # 1. print('1.') if 1+1 == 2: print('1+1是等于2的') print('1+1还是等于2的') print('1+1就等于2的') # 2 ...

  2. 记一次线上频繁fullGc的排查解决过程

    发生背景 最近上线的一个项目几乎全是查询业务,并且都是大表的慢查询,sql优化是做了一轮又一轮,前几天用户反馈页面加载过慢还时不时的会timeout,但是我们把对应的sql都优化一遍过后,前台响应还是 ...

  3. RocketMQ 在物流行业的应用与运维

    本文作者:丁威 - 中通快递资深架构师,<RocketMQ技术内幕>作者,Apache RocketMQ社区首席布道师,公众号「中间件兴趣圈」维护者. 01 物流行业的业务特点 物流行业有 ...

  4. Pinely Round 1 (Div. 1 + Div. 2)

    比赛链接 A 题意 构造两个长为 \(n\) 排列,使得两排列有长为 \(a\) 公共前缀和长为 \(b\) 的公共后缀. 题解 知识点:构造. 注意到,当 \(a+b\leq n-2\) 时,中间段 ...

  5. springMVC环境的搭建(一)

    概要: MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器(Controller). MV ...

  6. ThinkPHP6.0在phpstorm添加查询构造器和模型的代码提示

    ThinkPHP6.0升级后 使用查询构造器和模型都没有了提示 原因是tp6源码中没有添加注释 找到Model.php * @method Query where(mixed $field, stri ...

  7. Js前端导出csv

    var myMemory = myObjectStore.objectStore; var myDataArray = myMemory.data; var myCsvString = "\ ...

  8. WeetCode3 暴力递归->记忆化搜索->动态规划

    笔者这里总结的是一种套路,这种套路笔者最先是从左程云的b站视频学习到的 本文进行简单总结 系列文章目录和关于我 一丶动态规划的思想 使用dp数组记录之前状态计算的最佳结果,找出当前状态和之前状态的关系 ...

  9. 【离线数仓】Day04-即席查询(Ad Hoc):Presto链接不同数据源查询、Druid建多维表、Kylin使用cube快速查询

    一.Presto 1.简介 概念:大数据量.秒级.分布式SQL查询engine[解析SQL但不是数据库] 架构 不同worker对应不同的数据源(各数据源有对应的connector连接适配器) 优缺点 ...

  10. 20W,PD快充协议芯片,带有PPS控制器的USB-PD3.0

    JD6621是高度集成的USB供电(PD)控制器,支持USB PD 3.0 ,该USB PD 3.0 具有针对USB Type-C下游接口(源)设计的可编程电源( PPS)规范. 它监视CC引脚以检测 ...