我有一个应用程序,每晚发送几十个电子邮件,所以为了加快处理添加了一些cfthreads。
这导致了一些奇怪的错误,我发现在一个线程中创建的变量正被另一个线程修改。从我读过的文档中,在一个线程中创建的变量应仅对该线程可见?
做了一个简单的测试:
<cfthread
name="thread1"
action="run">
<cfsavecontent variable="local.template_body">
<cfinclude template="templates\6\2\bulletin_template.cfm">
</cfsavecontent>
<cfset tmpEmailBody = template_body>
</cfthread>
<cfthread
name="thread2"
action="run">
<cffile action="append"
file="C:\inetpub\error1.txt"
output="#tmpEmailBody#">
</cfthread>
“tmpEmailBody”的内容已成功写入文件。
奇怪的是,如果我删除cfsavecontent部分,并具有:
<cfset tmpEmailBody = "test">
,然后第二个线程引发错误,tmpEmailBody没有被定义,正如我所期望的那样。
任何人都知道这里发生了什么?
答案 0 :(得分:0)
我相信你的cfthread运行错误的目的。似乎线程2中的tmpEmailBody依赖于thread1。您不应该在单独的线程中运行相关代码..
与邮件有关的更好地使用cfthread可能是
Thread1 { 从数据库中选择电子邮件,其中电子邮件从a-m开始 出你的a-m列表 }
线程2 { 从电子邮件从n-z开始的数据库中选择电子邮件} 你的名单n-z }
两个线程同时运行。这两个查询可以同时进行,但你不能将变量保存在一个线程中,并希望它与另一个线程中的调用时间匹配。
答案 1 :(得分:0)
变量tmpEmailBody
正在Variables
范围内创建,而不是在仅限于该线程的范围内。线程将以随机顺序和随机时间执行,因此导致错误,因为thread1
在thread2
执行其第一行之前未执行其最后一行。
使用cfthread时,所有正常范围都不是线程安全的(而不是对ColdFusion请求线程的线程安全;也就是页面线程)如果要确保在一个线程中创建/使用的变量与所有线程隔离其他线程则必须使用线程范围。这在ColdFusion文档中正式记录为Using thread data。
我猜想你在两个线程之外声明tmpEmailBody
,但是因为将cfset更改为静态字符串会给出预期的行为,我会说cfsavecontent
存在“问题”,它写入Variables
范围而不是线程局部范围,该范围应归档为another scoping gotcha。
由于ColdFusion文档示例有一些不足之处,我将重写您的代码,就像您想要将电子邮件正文从一个线程传递到另一个线程一样。您已经说过这不是您的预期用途,但会显示各种线程范围。以下代码在不需要时将值复制到不同的范围中,但希望能够使不同的范围更清晰。并且,正如其他人所说,下面的任务是线程使用不当。
<cfthread
name="thread1"
action="run">
<cfset var template_body = "">
<cfsavecontent variable="template_body">
<cfinclude template="templates\6\2\bulletin_template.cfm">
</cfsavecontent>
<cfset thread.tmpEmailBody = template_body>
</cfthread>
<cfthread action="join" name="thread1" timeout="60">
<cfset Variables.tmpEmailBody = cfthread["thread1"]tmpEmailBody>
<cfthread
name="thread2"
action="run"
emailBody="#Variables.tmpEmailBody#">
<cffile action="append"
file="C:\inetpub\error1.txt"
output="#Attributes.emailBody#">
</cfthread>