我正在尝试使用一个可能有60000条记录的表在Excel中创建一个报表,所以我已经有了这样做的功能并且它可以工作,问题是当表实际上有这么多的记录时它也会持续很多,应用程序死了。我认为解决方案是将该函数放在一个Thread中并运行它后台,但似乎Thread开始执行然后它就停止了。我是这样做的:
首先我创建一个txt文件并检查它是否已创建,如果是,我创建了创建Excel文件的线程。这个函数也会在完成后编辑隐藏字段的值,这是因为当线程启动时我切换到多视图控件中的另一个视图并使用timmer我检查隐藏字段的值何时更改为我知道文件已完成。
Protected Sub ButtonExcel2003_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles ButtonExcel2003.Click
'This function saves a config file
SaveConfigFile()
'Here I check if the file was created
If File.Exists(Server.MapPath("./Downloads/Configs.txt")) Then
Try
'FillExcel creates the excel file
Dim t As New Thread(New ThreadStart(AddressOf Me.FillExcel))
t.Start()
'I have a Multiview Control, I want that while the excel file is being created show the view number 2 that says "creating"
Me.MultiView.ActiveViewIndex = 2
Catch ex As Exception
Me.Label2.Text = ex.Message
End Try
Else
MsgBox1.ShowMessage("Couldn't create the file")
End If
End Sub
这是FillExcel方法
Private Sub FillExcel()
_IsProcessing = True
Dim Celdas(13) As String
Celdas(0) = "A"
Celdas(1) = "B"
Celdas(2) = "C"
Celdas(3) = "D"
Celdas(4) = "E"
Celdas(5) = "F"
Celdas(6) = "G"
Celdas(7) = "H"
Celdas(8) = "I"
Celdas(9) = "J"
Celdas(10) = "K"
Celdas(11) = "L"
Celdas(12) = "M"
Try
If (File.Exists(Me.sourcefile)) Then
File.Delete(Me.sourcefile)
End If
'Template Name
File.Copy(Me.CopySourceFile, Me.sourcefile)
Catch ex As Exception
Me._FinExcel = -1
Me._IsProcessing = False
Exit Sub
End Try
Dim strConex As String = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & Me.sourcefile & ";" & _
"Extended Properties='Excel 8.0;HDR=NO;ReadOnly=0;'"
Dim conexion As New OleDbConnection(strConex)
Dim cmd2 As New OleDbCommand("", conexion)
Try
If (conexion.State = ConnectionState.Closed) Then conexion.Open()
If Me.IndexTipo = 0 And Me.Rows > 0 Then
tipo = "SI"
End If
Dim dt As DataTable = getData(tipo, Periodo, 0, -1)
If dt.Rows.Count > 0 Then
If dt.Rows.Count <= 65536 Then
'Is 2003 version
Dim cols = dt.Columns.Count - 1
Dim i = 1
Dim r As DataRow
If i = 1 Then
For j As Integer = 0 To cols
cmd2.CommandText = "UPDATE [Hoja1$" & Celdas(j) & (i).ToString & ":" & Celdas(j) & (i).ToString & "] SET F1='" & gridviewens.HeaderRow.Cells(j).Text & "'"
cmd2.ExecuteNonQuery()
Next
End If
For Each r In dt.Rows
i += 1
For j As Integer = 0 To cols
cmd2.CommandText = "UPDATE [Hoja1$" & Celdas(j) & (i).ToString & ":" & Celdas(j) & (i).ToString & "] SET F1='" + r(j).ToString & "'"
cmd2.ExecuteNonQuery()
Next
Next
Me._FinExcel = 1
Me._IsProcessing = False
ElseIf dt.Rows.Count > 65536 Then
If (conexion.State = ConnectionState.Open) Then conexion.Close()
Me._FinExcel = 2
Me._IsProcessing = False
End If
Else
'No data to generate
If (conexion.State = ConnectionState.Open) Then conexion.Close()
Me._FinExcel = 0
Me._IsProcessing = False
End If
Catch ex As Exception
If (conexion.State = ConnectionState.Open) Then conexion.Close()
Me._FinExcel = -1
Me._IsProcessing = False
End Try
If (conexion.State = ConnectionState.Open) Then conexion.Close()
_IsProcessing = False
End Sub
答案 0 :(得分:0)
如果从ASP.NET页面启动线程,则必须在分派页面之前完成。在页面启动的所有线程终止之前,不会调度该页面。在调度页面之前,asp.net页面等待所有线程加入。因此,在这种情况下,您无法从单独的线程中获得任何收益。
然而,asp.net的好处是我们有办法持久化对象。例如会话,应用程序,查看状态等。
在这种情况下,我通常会创建一个对象并将其保存在会话变量中。我让对象完成所有工作,并通过UpdatePanel
等(或任何其他方法)跟踪页面上的进度。
这是如何解决它的骨架。我相信你可以根据自己的需要调整这个解决方案。您需要自己放置MultiView,错误处理等。为了保持答案,我在这里省略了它。
在aspx页面上放置ScriptManager,Timer和UpdatePanel。在UpdatePanel中添加标签和按钮以跟踪进度。您可以稍后根据需要自定义UpdatePanel的外观。
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="WebForm1.aspx.vb" Inherits="WebApplication1.WebForm1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<asp:Timer ID="Timer1" runat="server" Enabled="false" Interval="1000" ></asp:Timer>
<div>
<h1>Long Running Task Demo</h1>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:Label runat="server" ID="ProgressLabel" Text="Click the Button to write Excel file." />
<asp:Button ID="Button1" runat="server" Text="Button" />
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Timer1" EventName="Tick" />
</Triggers>
</asp:UpdatePanel>
</div>
</form>
</body>
</html>
打开代码隐藏文件并添加以下代码。 (请注意,我已将FillExcel
方法移到另一个类中。)
Public Class WebForm1
Inherits System.Web.UI.Page
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
' create an object of our WriteExcelFileAsync class
Dim AsyncExcelFileWriter As New WriteExcelFileAsync(Server.MapPath("./Downloads/Configs.txt"))
AsyncExcelFileWriter.DoWork()
' save the object in session variable so that it can be retrieved back
Session("AsyncExcelFileWriter") = AsyncExcelFileWriter
' enable the timer
Timer1.Enabled = True
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
' retrieve the WriteExcelFileAsync object back from session variable
Dim AsyncExcelFileWriter As WriteExcelFileAsync = Session("AsyncExcelFileWriter")
If AsyncExcelFileWriter IsNot Nothing AndAlso AsyncExcelFileWriter.IsProcessing Then
' if it has not finished doing work (writing file) yet, show progress message..
' customize this as per your needs
ProgressLabel.Text = "Writing file... Please wait...blah blah blah..."
Else
' if the work is complete, show appropriate message
ProgressLabel.Text = "Finished writing file."
' disable the timer
Timer1.Enabled = False
' remove the object from memory and session variable
If AsyncExcelFileWriter IsNot Nothing Then
AsyncExcelFileWriter = Nothing
Session.Remove("AsyncExcelFileWriter")
End If
End If
End Sub
End Class
Public Class WriteExcelFileAsync
Private SourceFile As String
Private _IsProcessing As Boolean
Public ReadOnly Property IsProcessing As Boolean
Get
Return _IsProcessing
End Get
End Property
Public Sub New(sourceFile As String)
Me.SourceFile = sourceFile
End Sub
Public Sub DoWork()
Dim th As New Threading.Thread(AddressOf DoWorkTh)
th.Start()
End Sub
Private Sub DoWorkTh()
_IsProcessing = True
FillExcel()
_IsProcessing = False
End Sub
Private Sub FillExcel()
'your FillExcel method...
'write your file here
End Sub
End Class