Gri*_*ari 2 coldfusion cfthread cfloop lucee
我正在创建一个简单的电子邮件服务器状态页面,该页面调用两个不同的 CFC。
状态页要求:
输出类似于以下内容:
MyServerName - <up arrow>
MyServerName2 - <up arrow>
MyServerName3 - <up arrow>
MyServerName4 -<down arrow>
代码:
RetrieveEmailServers = APPLICATION.selectQueries.RetrieveEmailServers()
if (RetrieveEmailServers.recordCount) {
for(i = 1; i <= RetrieveEmailServers.recordCount(); i++) {
LOCAL.theDomains = RetrieveEmailServers.check_servers_domain[i];
LOCAL.theNames = RetrieveEmailServers.check_servers_name[i];
thread action="run" name="thread#i#" theDomains="#LOCAL.theDomains#" theNames="#LOCAL.theNames#" {
VARIABLES.theServers = APPLICATION.emailCheck.checkSMTPServer('#domains#',25,'','');
}
}
thread action="join" timeout="6000"{}
for(i = 1; i <= RetrieveEmailServers.recordCount(); i++) {
VARIABLES.theResult = cfthread["thread#i#"];
if (VARIABLES.theResult.theServers) {
LOCAL.theStatus = "<i class='fad fa-angle-double-up text-success fs-1'></i>"
}
else {
LOCAL.theStatus = "<i class='fad fa-angle-double-down text-danger fs-1'></i>"
}
writeOutput(ATTRIBUTES.theNames & " - " & LOCAL.theStatus & "<br>");
}
}
else {
writeOutput("No servers listed at this time.")
}
Run Code Online (Sandbox Code Playgroud)
错误:键[THESERVERS]不存在,结构为空
审议:
threadData()['thread#i#'].status;或类似可能是对cfthread[].该Attributes范围仅用于保存传递到线程中的值。因此,作用域是短暂的,仅存在于线程内。每个线程都有自己的“属性”范围,该范围在该线程运行之前或完成之后不存在。
例如,此代码片段传入名为“theDomains”的属性。该变量Attributes.theDomains只存在于线程内部。
thread action="run" name="thread1" theDomains="example.com" {
writeDump( attributes.theDomains );
}
thread action="join" name="thread1" {};
writeOutput( thread1.output );
Run Code Online (Sandbox Code Playgroud)
“线程局部”是另一个短暂的作用域,其目的是保存仅在线程内使用的变量。每个线程都有自己的私有“本地”范围,与所有其他线程分开。与attributes作用域一样,它仅在线程执行时存在,并在线程完成时被清除。
例如,此代码片段创建一个名为“MyLocalVar”的局部变量。显示线程output表明该变量存在于线程中
thread action="run" name="thread1" {
// Un-scoped v
myLocalVar = "foo";
writeOutput( "myLocalVar ="& myLocalVar );
}
thread action="join" name="thread1" {};
writeOutput( thread1.output );
Run Code Online (Sandbox Code Playgroud)
但是在线程完成后尝试访问它会导致错误
// fails with error "key [MYLOCALVAR] doesn't exist"
writeOutput( "myLocalVar ="& thread1.myLocalVar );
Run Code Online (Sandbox Code Playgroud)
Thread范围瞄准镜Thread的使用寿命更长。它旨在存储“..线程特定的变量和有关线程的元数据......”。更重要的是,该作用域可用于将信息传递回调用页面(甚至其他线程)。
例如,此代码片段创建一个线程范围的变量,即使在线程完成其执行之后,该变量对调用页面也是可见的:
thread action="run" name="thread1" {
// use scope prefix "thread."
thread.myThreadVar = "foo";
}
thread action="join" name="thread1" {};
writeOutput( "thread1.myThreadVar="& thread1.myThreadVar );
writeDump( thread1 );
Run Code Online (Sandbox Code Playgroud)
当您花了几天时间查看错误时,很容易忘记基础知识:) 处理未定义错误的第一件事是转储对象,并在尝试使用它之前查看是否确实包含您期望的内容。
for(i = 1; i <= RetrieveEmailServers.recordCount(); i++) {
VARIABLES.theResult = cfthread["thread#i#"];
writeDump( variables.theResult );
/* temporarily comment out rest of code
...
*/
}
Run Code Online (Sandbox Code Playgroud)
转储VARIABLES.theResult显示线程实际上因不同的错误而失败
由于线程内的属性名称错误。应该是attributes.theDomains,不是domains。
thread ...{
APPLICATION.emailCheck.checkSMTPServer( attributes.theDomains, ... );
}
Run Code Online (Sandbox Code Playgroud)
另一个线程转储显示错误消息并没有说谎。theServers由于作用域不正确,线程实际上不包含名为 的变量。使用thread范围,而不是“变量”。
thread ...{
thread.theServers = ....;
}
Run Code Online (Sandbox Code Playgroud)
即使修复了前两个问题后,您仍然会在这里收到另一个错误
for(i = 1; i <= RetrieveEmailServers.recordCount(); i++) {
...
writeOutput(ATTRIBUTES.theNames & " - " & LOCAL.theStatus & "<br>");
}
Run Code Online (Sandbox Code Playgroud)
请记住,attributes作用域仅存在于线程内。所以显然一旦线程完成就不能使用它。也可以存储theNames在thread范围中,或者由于您正在循环查询,因此使用查询列值RetrieveEmailServers.the_query_column_name[ i ]。
最后一个潜在问题。join 语句实际上并不等待您创建的线程。它只是等待 6000 毫秒。如果由于某种原因任何线程花费的时间超过该时间,您在尝试检索线程结果时将会收到错误。要实际等待创建的线程,您必须使用thread action="join" name=(list of thread names) {}. 我将把它作为读者的练习(:
说实话,还有其他事情可以清理和/或改进,但希望这个冗长的杂乱线程解释了为什么首先发生错误以及如何在将来使用线程时避免它们