程序库: 多功能测试仪 - 页 30

 
Stanislav Korotky #:

我在源代码更改中没有看到对剪贴板做了处理。

  static bool GetSettings2( string &Str, const int Attempts = 10 )
  {
    bool Res = false;

    if (MTTESTER::LockWaiting())
    {
      Res = MTTESTER::GetSettings(Str, Attempts);

      MTTESTER::Lock(false);
    }

    return(Res);
  }

如果运行优化,不是会同时占用所有可用核心吗?我不明白一个测试如何从优化中 "拿走 "了一个核心(事实上,即使是 2 个优化 MT 的代理也被标记为禁用)。

我想我马上就写出来了。优化终端有两个禁用代理。每个启用的代理占用一个核心。

 
fxsaber #:

我想我马上就写出来了。优化终端有两个禁用的代理。每个启用的代理都需要一个内核。

它没有明确提到手动 禁用(或代理的其他配置)--而这一细微差别仍然被绕过了。这就是我对并行工作的自动化程度提出疑问的根本原因。我天真地以为,从主题和博客描述来看,已经实现了完全自动化。

锁定等待(LockWaiting)已经出现了--这是我制定的锁定文件工作的方法。很明显,锁可以用来访问资源,包括剪贴板。术语混乱。

PS.也许我误解了什么,但如果只需要对剪贴板进行独占访问,那么对剪贴板本身的功能(OpenClipboard,源代码中已经提到)进行同样的锁定(定期检查的循环)会更合理。

 
Stanislav Korotky #:

它没有明确提到手动 禁用(或以其他方式配置代理)--而这一细微差别仍然被绕过了。这正是我对并行工作的自动化程度有疑问的原因。我天真地以为,从主题和博客描述来看,已经实现了完全自动化。

在 MQ 方面实现了完全自动化。在任何机器上,即使只使用一个终端,我也会关闭 1-2 个代理,这样我就可以在机器上无延迟地工作。


终端 1(优化):代理 3000-3017 - 启用,30018-3019 - 禁用。所有终端都是如此,因为所有其他终端都是第一个终端的完整副本。无需手动设置。

终端 2 - 用于单次通行。


有两种情况。

  1. 首先,我在终端 1 上运行优化,3000-3017 被打开。然后在终端 2 上进行单通 - 3018 正常。
  2. 首先在终端 2 上运行单程,3000 亮起。然后在终端 1 上进行优化 - 运行 3001-3018。
在 MQ 端,一切都是自动化的。你只需一分钟就能检查完毕。对话则需要更多时间。
 
Stanislav Korotky #:

PS.我可能误解了什么,但如果只需要对剪贴板进行例外访问,那么对剪贴板本身的功能(OpenClipboard,源代码中已经提到)进行同样的锁定(循环并定期检查)会更合乎逻辑。

我不明白这种解决方案的逻辑。

 
fxsaber #:

MQ 方面完全自动化。在任何一台机器上,即使我使用一个终端工作,我也会关闭 1-2 个代理,这样我就可以在机器上无延迟地工作。


终端 1(优化):代理 3000-3017 - 启用,30018-3019 - 禁用。所有终端都是如此,因为所有其他终端都是第一个终端的完整副本。无需手动设置。

终端 2 - 用于单次通行。


两种情况。

  1. 首先,我在终端 1 上运行优化,3000-3017 正在运行。然后,我在终端 2 上运行了单曲 - 3018 正在运行。
  2. 首先在终端 2 上运行单曲,运行 3000。然后在终端 1 上进行优化 - 3001-3018 正常。
在 MQ 端,一切都是自动化的。你只需一分钟就能检查完毕。对话要花费更多时间。

如果博客里有这样的描述,就不会有问题了。同样,我认为这种描述是指代理的手动配置,而不是自动化。没有什么可检查的。

 
Stanislav Korotky #:

如果博客中有这样的描述,就不会有问题了。再说一遍,在我看来,这段描述意味着代理的手动配置,而不是自动化。没有什么可检查的。

没有手动配置。您对代理什么都做不了,其行为也不会改变。令人惊讶。

 
fxsaber #:

没有手动配置。你什么也不能做,代理的行为不会改变。令人惊讶。

有人说 "是为了避免与并行测试人员一起工作时可能发生的冲突"。就内核而言,这句话具有误导性,因为实际上要做的是对代理进行手动配置。出于某种原因,您坚持将端口分配与内核联系起来。端口是不能重叠的,但内核(进程)可以,只是取决于预配置。我想我们只是对并行进程间自动冲突解决的概念不同而已。

 
Stanislav Korotky #:

有人说这是 "为了避免与并行测试人员工作时可能发生的冲突"。就内核而言,这句话具有误导性,因为事实上代理的手动配置是要进行的。

你误解了 "规避 "一词。当多个终端同时使用剪贴板工作时,问题就出现了。以前,一个终端的作业可能会意外进入另一个终端。现在这种情况已被排除。

 

MTTester.mqh 中有以下更改。

  • GetLastTstCacheFileName 现在只返回 tst 文件的名称,而不返回路径。
  • GetLastTstCache 能够获取与刚完成的测试相对应的 tst 文件。这可防止获取错误的 tst 文件。
  • 即使测试仪在按下开始按钮后立即做出反应,ClickStart 也能正常工作。在这种情况下,ClickStart 会识别出启动按钮已被成功按下。
 

有时,您需要在工作终端上做同样的事情。该操作的自动化示例如下。


需要通过运行类似的脚本RunMe.mq5 在每个终端上收集数据。

#include <fxsaber\MultiTester\MTTester.mqh> //https://www.mql5.com/zh/code/26132
  
void OnStart()
{
  if (MTTESTER::LockWaiting()) // 如果要按顺序执行操作。
  {
    const int handle = ::FileOpen(__FILE__, FILE_WRITE | FILE_READ | FILE_ANSI | FILE_COMMON);

    // 将所需数据写入文件。
    if (handle != INVALID_HANDLE)      
    {
      FileSeek(handle, 0, SEEK_END);
      FileWriteString(handle, "Account = " + (string)AccountInfoInteger(ACCOUNT_LOGIN) + ", " +
                              "Balance = " + (string)AccountInfoDouble(ACCOUNT_BALANCE) + "\n");
      
      FileClose(handle);
    }

    MTTESTER::Lock(false); // 释放并行执行锁。
  }
}


就是这样做的。

// 在所有终端上运行脚本。

#include <fxsaber\MultiTester\MTTester.mqh> //https://www.mql5.com/zh/code/26132
  
void OnStart()
{
  HANDLE Handles[]; 
  
  // 运行所有终端
  for (int i = MTTESTER::GetTerminalHandles(Handles) - 1; i >= 0; i--)
    MTTESTER::RunEX5("Scripts\\RunMe.ex5", Handles[i], true); // 并分别运行相应的脚本。
}


结果,我们只需单击一次,就收集到了所有终端的数据。感谢MTTESTER::RunEX5- 在所需终端上运行 EX5(便携式)。