Coldfusion/Lucee多线程读取大Excel文件结果异常问题求助
问题分析与解决方案
你的问题核心在于线程作用域隔离以及多线程读取同一文件的设计误区,我来一步步拆解并解决:
为什么输出的是0?
你在主线程里定义了<cfset var _Qry = 0 />,但每个<cfthread>标签内部是独立的线程作用域——也就是说,子线程里的_Qry和主线程的_Qry完全是两个毫无关联的变量。子线程里的查询结果根本不会同步到主线程的变量中,所以最后主线程输出的还是初始值0。
另外还有个隐藏问题:10个线程同时读取同一个Excel文件,很可能会触发文件锁定、读取数据不完整甚至直接抛出异常,这种做法本身就不合理,因为你是要读取整个文件,不是分块并行处理。
正确的并行读取方案
如果想加速大Excel的读取,应该采用分块读取的思路:把Excel的内容分成多个块,每个线程负责读取一块数据,最后在主线程合并所有结果。
修正后的代码示例
<cfset threadResults = [] /> <!--- 先获取Excel的总行数,用于计算分块范围 ---> <cfspreadsheet action="read" src="#arguments._file#" sheet="1" getInfo="true" result="sheetInfo"> <cfset totalRows = sheetInfo.rowCount - 1> <!--- 减去表头行 ---> <cfset rowsPerThread = ceiling(totalRows / 10)> <!--- 每个线程负责的行数 ---> <cfloop from="1" to="10" index="idx"> <cfset startRow = (idx - 1)*rowsPerThread + 2> <!--- 表头是第1行,所以数据从第2行开始 ---> <cfset endRow = min(idx*rowsPerThread + 1, sheetInfo.rowCount)> <!--- 处理最后一块的边界 ---> <cfthread name="Thread#idx#" action="run" src="#arguments._file#" startRow="#startRow#" endRow="#endRow#"> <!--- 读取当前线程负责的行范围 ---> <cfspreadsheet action="read" src="#src#" sheet="1" query="localThreadQry" headerrow="1" excludeHeaderRow="true" rows="#startRow#-#endRow#"> <!--- 将查询结果存入线程作用域,供主线程获取 ---> <cfset thread.currentChunk = localThreadQry> </cfthread> </cfloop> <!--- 等待所有线程执行完成 ---> <cfloop from="1" to="10" index="idx"> <cfthread name="Thread#idx#" action="join" /> <!--- 收集每个线程的查询结果 ---> <cfset arrayAppend(threadResults, cfthread["Thread#idx#"].currentChunk)> </cfloop> <!--- 合并所有分块的查询结果 ---> <cfset finalQuery = queryNew("")> <cfloop array="#threadResults#" index="chunkQry"> <!--- 如果当前块没有数据,跳过 ---> <cfif chunkQry.recordCount == 0> <cfcontinue> </cfif> <!--- 初始化最终查询的列(第一次循环时) ---> <cfif finalQuery.columnList is ""> <cfset queryNew(chunkQry.columnList, chunkQry.columnTypes, finalQuery)> </cfif> <!--- 将当前块的每一行添加到最终查询 ---> <cfloop query="chunkQry"> <cfset queryAddRow(finalQuery)> <cfloop list="#chunkQry.columnList#" index="colName"> <cfset querySetCell(finalQuery, colName, chunkQry[colName])> </cfloop> </cfloop> </cfloop> <cfdump var="#finalQuery#">
关键要点说明
- 分块读取:先获取Excel总行数,平均分配给10个线程,每个线程读取指定的行范围,避免了多线程同时读取整个文件的冲突。
- 线程结果传递:子线程把查询结果存入
thread.xxx作用域,主线程在join后通过cfthread["线程名"].xxx获取结果。 - 结果合并:将所有线程返回的分块查询,合并成一个完整的查询对象,得到最终的Excel数据。
内容的提问来源于stack exchange,提问作者edam
相关产品推荐
相关产品推荐

