Long-running Process with Responsive Form - Performance Improvements












0















So, I'm working on a library for my internal applications that interacts with our PostgreSQL database (amongst many other things). One requirement at the moment is that this library can dump data from the database to a file. I have something working, but I've been trying to improve its performance as much as possible. This is what I'm currently looking at:



Using COPYReader As NpgsqlCopyTextReader = CType(CIADB.DBConnection.BeginTextExport(COPYSQL), NpgsqlCopyTextReader)
With COPYReader
Dim stopWatch As New Stopwatch
Dim ts As TimeSpan
Dim elapsedTime As String

' ** FIRST ATTEMPT
stopWatch.Start()
Dim BufferText As String = .ReadLine

Do While Not BufferText Is Nothing
CurrentPosition += 1
OutputFile.WriteLine(BufferText)

If Not UpdateForm Is Nothing Then
UpdateForm.UpdateProgress(Convert.ToInt32((CurrentPosition / MaxRecords) * 100))
End If

BufferText = .ReadLine
Loop

OutputFile.Flush()
OutputFile.Close()

stopWatch.Stop()
ts = stopWatch.Elapsed
elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10)

' ** FIRST ATTEMPT RESULTS
' ** Records Retrieved: 65358
' ** Time To Complete: 2:12.07
' ** Lines Written: 65358
' ** File Size: 8,166 KB

' ** SECOND ATTEMPT
stopWatch.Start()

Using TestOutputFile As New IO.StreamWriter(DestinationFile.FullName.Replace(".TXT", "_TEST.TXT"), False)
TestOutputFile.Write(.ReadToEndAsync.Result)
End Using

stopWatch.Stop()
ts = stopWatch.Elapsed
elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10)

' ** SECOND ATTEMPT
' ** Records Retrieved: 65358
' ** Time To Complete: 1:04.01
' ** Lines Written: 65358
' ** File Size: 8,102 KB
End With
End Using


I've run multiple tests of each method and come up with pretty much the same results. FIRST ATTEMPT takes about twice as long as SECOND ATTEMPT



Obviously, the UpdateForm.UpdateProgress method used in FIRST ATTEMPT (used to keep the form responsive and show the current progress of the export) is going to cause the process to take longer because of the form updating and such involved, not to mention the line-by-line writing to the file. This is pretty much exactly why I was looking at reducing the number of extra calls by doing a full dump in one line of code. The problem is that if I use the "one-liner", the form is completely unresponsive until the process is complete.



I've tried moving the code for the "all-in-one-shot" dump from the SECOND ATTEMPT into a separate Async method, but I'm extremely unfamiliar with async methods in general, so I'm (obviously) not doing it right:



Private Async Sub OutputToFile(ByVal COPYReader As NpgsqlCopyTextReader, ByVal DestinationFile As IO.FileInfo)
' ** METHOD 3
Using TestOutputFile As New IO.StreamWriter(DestinationFile.FullName.Replace(".TXT", "_TEST.TXT"), False)
Await TestOutputFile.WriteAsync(COPYReader.ReadToEndAsync.Result)
End Using

' ** METHOD 3 RESULTS
' ** Records Retrieved: 65358
' ** Time To Complete: 0:15.07
' ** Lines Written: 34
' ** File Size: 4 KB
End Sub


One other thing to mention: I tried moving all of this to a BackgroundWorker, but I was getting some strange behavior when I tried to call my UpdateForm.UpdateProgress method which caused the application to completely skip the actual dumping process. I've currently given up on trying to get this onto a separate thread, but I'm still open to other suggestions. This is actually one of the smaller tables that I'm dumping, so I'm not looking forward to what one of the bigger ones will do.



Just for the sake of completeness, here's the UpdateForm class that I've implemented in my library for reusability across other applications:



Imports System.Windows.Forms

Namespace Common
Public Class FormHandler
Implements IDisposable

Public Property ApplicationForm As Form
Public Property ApplicationStatusLabel As Label
Public Property ApplicationToolStripLabel As ToolStripStatusLabel
Public Property ApplicationProgressBar As ProgressBar

Private LabelVisibleState As Boolean = True
Private ProgressBarVisibleState As Boolean = True
Private CurrentStatusText As String
Private CurrentProgress As Integer

Public Sub New(ByVal AppForm As Form)
ApplicationForm = AppForm
End Sub

Public Sub New(ByVal StatusLabel As Label, ByVal Progress As ProgressBar)
ApplicationStatusLabel = StatusLabel
ApplicationToolStripLabel = Nothing
ApplicationProgressBar = Progress
ApplicationForm = ApplicationProgressBar.Parent.FindForm

LabelVisibleState = StatusLabel.Visible
ProgressBarVisibleState = Progress.Visible

With ApplicationProgressBar
.Minimum = 0
.Maximum = 100
.Value = 0
.Visible = True
End With

With ApplicationStatusLabel
.Visible = True
.Text = ""
End With
End Sub

Public Sub New(ByVal StatusLabel As ToolStripStatusLabel, ByVal Progress As ProgressBar)
ApplicationToolStripLabel = StatusLabel
ApplicationStatusLabel = Nothing
ApplicationProgressBar = Progress
ApplicationForm = ApplicationProgressBar.Parent.FindForm

LabelVisibleState = StatusLabel.Visible
ProgressBarVisibleState = Progress.Visible

With ApplicationProgressBar
.Minimum = 0
.Maximum = 100
.Value = 0
.Visible = True
End With

With ApplicationToolStripLabel
.Visible = True
.Text = ""
End With
End Sub

Public Sub New(ByVal AppForm As Form, ByVal StatusLabel As Label, ByVal Progress As ProgressBar)
ApplicationForm = AppForm
ApplicationStatusLabel = StatusLabel
ApplicationToolStripLabel = Nothing
ApplicationProgressBar = Progress

LabelVisibleState = StatusLabel.Visible
ProgressBarVisibleState = Progress.Visible

With ApplicationProgressBar
.Minimum = 0
.Maximum = 100
.Value = 0
.Visible = True
End With

With ApplicationStatusLabel
.Visible = True
.Text = ""
End With
End Sub

Public Sub New(ByVal AppForm As Form, ByVal StatusLabel As ToolStripStatusLabel, ByVal Progress As ProgressBar)
ApplicationForm = AppForm
ApplicationToolStripLabel = StatusLabel
ApplicationStatusLabel = Nothing
ApplicationProgressBar = Progress

LabelVisibleState = StatusLabel.Visible
ProgressBarVisibleState = Progress.Visible

With ApplicationProgressBar
.Minimum = 0
.Maximum = 100
.Value = 0
.Visible = True
End With

With ApplicationToolStripLabel
.Visible = True
.Text = ""
End With
End Sub

Friend Sub UpdateProgress(ByVal StatusText As String, ByVal CurrentPosition As Integer, ByVal MaxValue As Integer)
CurrentStatusText = StatusText
CurrentProgress = Convert.ToInt32((CurrentPosition / MaxValue) * 100)
UpdateStatus()
End Sub

Friend Sub UpdateProgress(ByVal StatusText As String, ByVal PercentComplete As Decimal)
CurrentStatusText = StatusText
CurrentProgress = Convert.ToInt32(PercentComplete)
UpdateStatus()
End Sub

Friend Sub UpdateProgress(ByVal StatusText As String)
CurrentStatusText = StatusText
CurrentProgress = 0
UpdateStatus()
End Sub

Friend Sub UpdateProgress(ByVal PercentComplete As Decimal)
CurrentProgress = Convert.ToInt32(PercentComplete)
UpdateStatus()
End Sub

Friend Sub UpdateProgress(ByVal CurrentPosition As Integer, ByVal MaxValue As Integer)
CurrentProgress = Convert.ToInt32((CurrentPosition / MaxValue) * 100)
UpdateStatus()
End Sub

Friend Sub ResetProgressUpdate()
CurrentStatusText = ""
CurrentProgress = 0
UpdateStatus()
End Sub

Private Sub UpdateStatus()
If Not ApplicationForm Is Nothing Then
If ApplicationForm.InvokeRequired Then
Dim UpdateInvoker As New MethodInvoker(AddressOf UpdateStatus)

Try
ApplicationForm.Invoke(UpdateInvoker)
Catch ex As Exception
Dim InvokeError As New ErrorHandler(ex)

InvokeError.LogException()
End Try
Else
UpdateApplicationProgress(CurrentStatusText)
End If
End If
End Sub

Friend Sub UpdateApplicationProgress(ByVal ProgressText As String)
If Not ApplicationForm Is Nothing Then
With ApplicationForm
If Not ProgressText Is Nothing Then
If Not ApplicationStatusLabel Is Nothing Then
ApplicationStatusLabel.Text = ProgressText
End If

If Not ApplicationToolStripLabel Is Nothing Then
ApplicationToolStripLabel.Text = ProgressText
End If
End If

If Not ApplicationProgressBar Is Nothing Then
ApplicationProgressBar.Value = CurrentProgress
End If
End With

ApplicationForm.Refresh()
Application.DoEvents()
End If
End Sub

Public Sub Dispose() Implements IDisposable.Dispose
If Not ApplicationForm Is Nothing Then
ApplicationForm.Dispose()
End If

If Not ApplicationStatusLabel Is Nothing Then
ApplicationStatusLabel.Visible = LabelVisibleState
ApplicationStatusLabel.Dispose()
End If

If Not ApplicationToolStripLabel Is Nothing Then
ApplicationToolStripLabel.Visible = LabelVisibleState
ApplicationToolStripLabel.Dispose()
End If

If Not ApplicationProgressBar Is Nothing Then
ApplicationProgressBar.Visible = ProgressBarVisibleState
ApplicationProgressBar.Dispose()
End If
End Sub
End Class
End Namespace




EDIT



Per the suggestion in the comments from @the_lotus, I modified my FIRST ATTEMPT slightly to check the value of the current progress (I declared a CurrentProgress variable as an Integer), and it dramatically improved the time taken:



' ** FOURTH ATTEMPT
Using COPYReader As NpgsqlCopyTextReader = CType(CIADB.DBConnection.BeginTextExport(COPYSQL), NpgsqlCopyTextReader)
With COPYReader
Dim stopWatch As New Stopwatch
Dim ts As TimeSpan
Dim elapsedTime As String
Dim CurrentProgress As Integer = 0

stopWatch.Start()
Dim BufferText As String = .ReadLine

Do While Not BufferText Is Nothing
CurrentPosition += 1
OutputFile.WriteLine(BufferText)

' ** Checks to see if the value of the ProgressBar will actually
' ** be changed by the CurrentPosition before making a call to
' ** UpdateProgress. If the value doesn't change, don't waste
' ** the call
If Convert.ToInt32((CurrentPosition / MaxRecords) * 100) <> CurrentProgress Then
CurrentProgress = Convert.ToInt32((CurrentPosition / MaxRecords) * 100)

If Not UpdateForm Is Nothing Then
UpdateForm.UpdateProgress(CurrentProgress)
End If
End If

BufferText = .ReadLine
Loop

OutputFile.Flush()
OutputFile.Close()

stopWatch.Stop()
ts = stopWatch.Elapsed
elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10)
End With
End Using
' ** FOURTH ATTEMPT RESULTS
' ** Records Retrieved: 65358
' ** Time To Complete: 0:47.45
' ** Lines Written: 65358
' ** File Size: 8,166 KB


Of course, the form is a "little" less responsive than if I were making the call on every record, but I'm thinking it's worth the trade-off.





EDIT #2



So that I could minimize the amount of code I'd have to retype (read: "copy/paste") each time I use the UpdateProgress method, I've moved the test for changed values over there and it seems to be operating with the same performance improvements. Again, for the sake of completeness, here's the code for the two private methods involved in doing the actual progress/status update:



Private Sub UpdateStatus()
If Not ApplicationForm Is Nothing Then
If ApplicationForm.InvokeRequired Then
Dim UpdateInvoker As New MethodInvoker(AddressOf UpdateStatus)

Try
ApplicationForm.Invoke(UpdateInvoker)
Catch ex As Exception
Dim InvokeError As New ErrorHandler(ex)

InvokeError.LogException()
End Try
Else
UpdateApplicationProgress()
End If
End If
End Sub

Private Sub UpdateApplicationProgress()
Dim Changed As Boolean = False

If Not ApplicationForm Is Nothing Then
With ApplicationForm
If Not CurrentStatusText Is Nothing Then
If Not ApplicationStatusLabel Is Nothing Then
If ApplicationStatusLabel.Text <> CurrentStatusText Then
Changed = True
ApplicationStatusLabel.Text = CurrentStatusText
End If
End If

If Not ApplicationToolStripLabel Is Nothing Then
If ApplicationToolStripLabel.Text <> CurrentStatusText Then
Changed = True
ApplicationToolStripLabel.Text = CurrentStatusText
End If
End If
End If

If Not ApplicationProgressBar Is Nothing Then
If ApplicationProgressBar.Value <> CurrentProgress Then
Changed = True
ApplicationProgressBar.Value = CurrentProgress
End If
End If
End With

If Changed Then
ApplicationForm.Refresh()
End If

Application.DoEvents()
End If
End Sub


Doing it this way also came with the added benefit of returning some of the responsiveness to the form that was previously lost. I hope at least some of this code and information is helpful to someone out there.










share|improve this question




















  • 2





    Your second attempt might not even go to the database since it could be cached. Also, don't call UpdateProgress on each call. It's not necessary when the percentage didn't even move.

    – the_lotus
    Nov 21 '18 at 18:11






  • 1





    @the_lotus - HOLY CRAP! I added a small bit of code to check whether or not the current progress percentage has changed (see edit) before calling UpdateProgress, and it reduced the amount of time dramatically - down to 0:47:45! What a simple but significant thing to overlook! Thanks for that!

    – G_Hosa_Phat
    Nov 21 '18 at 18:20











  • Can someone please clarify why the downvote and vote to close as "opinion-based"? It is my intent to ask "good" questions and I attempt to provide clear examples of my attempts to answer/resolve the issues on my own so as not to add to the clutter of "poor" questions.

    – G_Hosa_Phat
    Nov 27 '18 at 16:38






  • 1





    Some people want stackoverflow to be a place for questions that can be answered with a very clear "one solution" code. In this case, there's not clear cut code for the implementation of a solution. I wouldn't worry to much.

    – the_lotus
    Nov 27 '18 at 16:46











  • Thanks for that. I was just asking because I want to know if there's anything I should be doing to improve the quality of my questions in general.

    – G_Hosa_Phat
    Nov 27 '18 at 16:54
















0















So, I'm working on a library for my internal applications that interacts with our PostgreSQL database (amongst many other things). One requirement at the moment is that this library can dump data from the database to a file. I have something working, but I've been trying to improve its performance as much as possible. This is what I'm currently looking at:



Using COPYReader As NpgsqlCopyTextReader = CType(CIADB.DBConnection.BeginTextExport(COPYSQL), NpgsqlCopyTextReader)
With COPYReader
Dim stopWatch As New Stopwatch
Dim ts As TimeSpan
Dim elapsedTime As String

' ** FIRST ATTEMPT
stopWatch.Start()
Dim BufferText As String = .ReadLine

Do While Not BufferText Is Nothing
CurrentPosition += 1
OutputFile.WriteLine(BufferText)

If Not UpdateForm Is Nothing Then
UpdateForm.UpdateProgress(Convert.ToInt32((CurrentPosition / MaxRecords) * 100))
End If

BufferText = .ReadLine
Loop

OutputFile.Flush()
OutputFile.Close()

stopWatch.Stop()
ts = stopWatch.Elapsed
elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10)

' ** FIRST ATTEMPT RESULTS
' ** Records Retrieved: 65358
' ** Time To Complete: 2:12.07
' ** Lines Written: 65358
' ** File Size: 8,166 KB

' ** SECOND ATTEMPT
stopWatch.Start()

Using TestOutputFile As New IO.StreamWriter(DestinationFile.FullName.Replace(".TXT", "_TEST.TXT"), False)
TestOutputFile.Write(.ReadToEndAsync.Result)
End Using

stopWatch.Stop()
ts = stopWatch.Elapsed
elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10)

' ** SECOND ATTEMPT
' ** Records Retrieved: 65358
' ** Time To Complete: 1:04.01
' ** Lines Written: 65358
' ** File Size: 8,102 KB
End With
End Using


I've run multiple tests of each method and come up with pretty much the same results. FIRST ATTEMPT takes about twice as long as SECOND ATTEMPT



Obviously, the UpdateForm.UpdateProgress method used in FIRST ATTEMPT (used to keep the form responsive and show the current progress of the export) is going to cause the process to take longer because of the form updating and such involved, not to mention the line-by-line writing to the file. This is pretty much exactly why I was looking at reducing the number of extra calls by doing a full dump in one line of code. The problem is that if I use the "one-liner", the form is completely unresponsive until the process is complete.



I've tried moving the code for the "all-in-one-shot" dump from the SECOND ATTEMPT into a separate Async method, but I'm extremely unfamiliar with async methods in general, so I'm (obviously) not doing it right:



Private Async Sub OutputToFile(ByVal COPYReader As NpgsqlCopyTextReader, ByVal DestinationFile As IO.FileInfo)
' ** METHOD 3
Using TestOutputFile As New IO.StreamWriter(DestinationFile.FullName.Replace(".TXT", "_TEST.TXT"), False)
Await TestOutputFile.WriteAsync(COPYReader.ReadToEndAsync.Result)
End Using

' ** METHOD 3 RESULTS
' ** Records Retrieved: 65358
' ** Time To Complete: 0:15.07
' ** Lines Written: 34
' ** File Size: 4 KB
End Sub


One other thing to mention: I tried moving all of this to a BackgroundWorker, but I was getting some strange behavior when I tried to call my UpdateForm.UpdateProgress method which caused the application to completely skip the actual dumping process. I've currently given up on trying to get this onto a separate thread, but I'm still open to other suggestions. This is actually one of the smaller tables that I'm dumping, so I'm not looking forward to what one of the bigger ones will do.



Just for the sake of completeness, here's the UpdateForm class that I've implemented in my library for reusability across other applications:



Imports System.Windows.Forms

Namespace Common
Public Class FormHandler
Implements IDisposable

Public Property ApplicationForm As Form
Public Property ApplicationStatusLabel As Label
Public Property ApplicationToolStripLabel As ToolStripStatusLabel
Public Property ApplicationProgressBar As ProgressBar

Private LabelVisibleState As Boolean = True
Private ProgressBarVisibleState As Boolean = True
Private CurrentStatusText As String
Private CurrentProgress As Integer

Public Sub New(ByVal AppForm As Form)
ApplicationForm = AppForm
End Sub

Public Sub New(ByVal StatusLabel As Label, ByVal Progress As ProgressBar)
ApplicationStatusLabel = StatusLabel
ApplicationToolStripLabel = Nothing
ApplicationProgressBar = Progress
ApplicationForm = ApplicationProgressBar.Parent.FindForm

LabelVisibleState = StatusLabel.Visible
ProgressBarVisibleState = Progress.Visible

With ApplicationProgressBar
.Minimum = 0
.Maximum = 100
.Value = 0
.Visible = True
End With

With ApplicationStatusLabel
.Visible = True
.Text = ""
End With
End Sub

Public Sub New(ByVal StatusLabel As ToolStripStatusLabel, ByVal Progress As ProgressBar)
ApplicationToolStripLabel = StatusLabel
ApplicationStatusLabel = Nothing
ApplicationProgressBar = Progress
ApplicationForm = ApplicationProgressBar.Parent.FindForm

LabelVisibleState = StatusLabel.Visible
ProgressBarVisibleState = Progress.Visible

With ApplicationProgressBar
.Minimum = 0
.Maximum = 100
.Value = 0
.Visible = True
End With

With ApplicationToolStripLabel
.Visible = True
.Text = ""
End With
End Sub

Public Sub New(ByVal AppForm As Form, ByVal StatusLabel As Label, ByVal Progress As ProgressBar)
ApplicationForm = AppForm
ApplicationStatusLabel = StatusLabel
ApplicationToolStripLabel = Nothing
ApplicationProgressBar = Progress

LabelVisibleState = StatusLabel.Visible
ProgressBarVisibleState = Progress.Visible

With ApplicationProgressBar
.Minimum = 0
.Maximum = 100
.Value = 0
.Visible = True
End With

With ApplicationStatusLabel
.Visible = True
.Text = ""
End With
End Sub

Public Sub New(ByVal AppForm As Form, ByVal StatusLabel As ToolStripStatusLabel, ByVal Progress As ProgressBar)
ApplicationForm = AppForm
ApplicationToolStripLabel = StatusLabel
ApplicationStatusLabel = Nothing
ApplicationProgressBar = Progress

LabelVisibleState = StatusLabel.Visible
ProgressBarVisibleState = Progress.Visible

With ApplicationProgressBar
.Minimum = 0
.Maximum = 100
.Value = 0
.Visible = True
End With

With ApplicationToolStripLabel
.Visible = True
.Text = ""
End With
End Sub

Friend Sub UpdateProgress(ByVal StatusText As String, ByVal CurrentPosition As Integer, ByVal MaxValue As Integer)
CurrentStatusText = StatusText
CurrentProgress = Convert.ToInt32((CurrentPosition / MaxValue) * 100)
UpdateStatus()
End Sub

Friend Sub UpdateProgress(ByVal StatusText As String, ByVal PercentComplete As Decimal)
CurrentStatusText = StatusText
CurrentProgress = Convert.ToInt32(PercentComplete)
UpdateStatus()
End Sub

Friend Sub UpdateProgress(ByVal StatusText As String)
CurrentStatusText = StatusText
CurrentProgress = 0
UpdateStatus()
End Sub

Friend Sub UpdateProgress(ByVal PercentComplete As Decimal)
CurrentProgress = Convert.ToInt32(PercentComplete)
UpdateStatus()
End Sub

Friend Sub UpdateProgress(ByVal CurrentPosition As Integer, ByVal MaxValue As Integer)
CurrentProgress = Convert.ToInt32((CurrentPosition / MaxValue) * 100)
UpdateStatus()
End Sub

Friend Sub ResetProgressUpdate()
CurrentStatusText = ""
CurrentProgress = 0
UpdateStatus()
End Sub

Private Sub UpdateStatus()
If Not ApplicationForm Is Nothing Then
If ApplicationForm.InvokeRequired Then
Dim UpdateInvoker As New MethodInvoker(AddressOf UpdateStatus)

Try
ApplicationForm.Invoke(UpdateInvoker)
Catch ex As Exception
Dim InvokeError As New ErrorHandler(ex)

InvokeError.LogException()
End Try
Else
UpdateApplicationProgress(CurrentStatusText)
End If
End If
End Sub

Friend Sub UpdateApplicationProgress(ByVal ProgressText As String)
If Not ApplicationForm Is Nothing Then
With ApplicationForm
If Not ProgressText Is Nothing Then
If Not ApplicationStatusLabel Is Nothing Then
ApplicationStatusLabel.Text = ProgressText
End If

If Not ApplicationToolStripLabel Is Nothing Then
ApplicationToolStripLabel.Text = ProgressText
End If
End If

If Not ApplicationProgressBar Is Nothing Then
ApplicationProgressBar.Value = CurrentProgress
End If
End With

ApplicationForm.Refresh()
Application.DoEvents()
End If
End Sub

Public Sub Dispose() Implements IDisposable.Dispose
If Not ApplicationForm Is Nothing Then
ApplicationForm.Dispose()
End If

If Not ApplicationStatusLabel Is Nothing Then
ApplicationStatusLabel.Visible = LabelVisibleState
ApplicationStatusLabel.Dispose()
End If

If Not ApplicationToolStripLabel Is Nothing Then
ApplicationToolStripLabel.Visible = LabelVisibleState
ApplicationToolStripLabel.Dispose()
End If

If Not ApplicationProgressBar Is Nothing Then
ApplicationProgressBar.Visible = ProgressBarVisibleState
ApplicationProgressBar.Dispose()
End If
End Sub
End Class
End Namespace




EDIT



Per the suggestion in the comments from @the_lotus, I modified my FIRST ATTEMPT slightly to check the value of the current progress (I declared a CurrentProgress variable as an Integer), and it dramatically improved the time taken:



' ** FOURTH ATTEMPT
Using COPYReader As NpgsqlCopyTextReader = CType(CIADB.DBConnection.BeginTextExport(COPYSQL), NpgsqlCopyTextReader)
With COPYReader
Dim stopWatch As New Stopwatch
Dim ts As TimeSpan
Dim elapsedTime As String
Dim CurrentProgress As Integer = 0

stopWatch.Start()
Dim BufferText As String = .ReadLine

Do While Not BufferText Is Nothing
CurrentPosition += 1
OutputFile.WriteLine(BufferText)

' ** Checks to see if the value of the ProgressBar will actually
' ** be changed by the CurrentPosition before making a call to
' ** UpdateProgress. If the value doesn't change, don't waste
' ** the call
If Convert.ToInt32((CurrentPosition / MaxRecords) * 100) <> CurrentProgress Then
CurrentProgress = Convert.ToInt32((CurrentPosition / MaxRecords) * 100)

If Not UpdateForm Is Nothing Then
UpdateForm.UpdateProgress(CurrentProgress)
End If
End If

BufferText = .ReadLine
Loop

OutputFile.Flush()
OutputFile.Close()

stopWatch.Stop()
ts = stopWatch.Elapsed
elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10)
End With
End Using
' ** FOURTH ATTEMPT RESULTS
' ** Records Retrieved: 65358
' ** Time To Complete: 0:47.45
' ** Lines Written: 65358
' ** File Size: 8,166 KB


Of course, the form is a "little" less responsive than if I were making the call on every record, but I'm thinking it's worth the trade-off.





EDIT #2



So that I could minimize the amount of code I'd have to retype (read: "copy/paste") each time I use the UpdateProgress method, I've moved the test for changed values over there and it seems to be operating with the same performance improvements. Again, for the sake of completeness, here's the code for the two private methods involved in doing the actual progress/status update:



Private Sub UpdateStatus()
If Not ApplicationForm Is Nothing Then
If ApplicationForm.InvokeRequired Then
Dim UpdateInvoker As New MethodInvoker(AddressOf UpdateStatus)

Try
ApplicationForm.Invoke(UpdateInvoker)
Catch ex As Exception
Dim InvokeError As New ErrorHandler(ex)

InvokeError.LogException()
End Try
Else
UpdateApplicationProgress()
End If
End If
End Sub

Private Sub UpdateApplicationProgress()
Dim Changed As Boolean = False

If Not ApplicationForm Is Nothing Then
With ApplicationForm
If Not CurrentStatusText Is Nothing Then
If Not ApplicationStatusLabel Is Nothing Then
If ApplicationStatusLabel.Text <> CurrentStatusText Then
Changed = True
ApplicationStatusLabel.Text = CurrentStatusText
End If
End If

If Not ApplicationToolStripLabel Is Nothing Then
If ApplicationToolStripLabel.Text <> CurrentStatusText Then
Changed = True
ApplicationToolStripLabel.Text = CurrentStatusText
End If
End If
End If

If Not ApplicationProgressBar Is Nothing Then
If ApplicationProgressBar.Value <> CurrentProgress Then
Changed = True
ApplicationProgressBar.Value = CurrentProgress
End If
End If
End With

If Changed Then
ApplicationForm.Refresh()
End If

Application.DoEvents()
End If
End Sub


Doing it this way also came with the added benefit of returning some of the responsiveness to the form that was previously lost. I hope at least some of this code and information is helpful to someone out there.










share|improve this question




















  • 2





    Your second attempt might not even go to the database since it could be cached. Also, don't call UpdateProgress on each call. It's not necessary when the percentage didn't even move.

    – the_lotus
    Nov 21 '18 at 18:11






  • 1





    @the_lotus - HOLY CRAP! I added a small bit of code to check whether or not the current progress percentage has changed (see edit) before calling UpdateProgress, and it reduced the amount of time dramatically - down to 0:47:45! What a simple but significant thing to overlook! Thanks for that!

    – G_Hosa_Phat
    Nov 21 '18 at 18:20











  • Can someone please clarify why the downvote and vote to close as "opinion-based"? It is my intent to ask "good" questions and I attempt to provide clear examples of my attempts to answer/resolve the issues on my own so as not to add to the clutter of "poor" questions.

    – G_Hosa_Phat
    Nov 27 '18 at 16:38






  • 1





    Some people want stackoverflow to be a place for questions that can be answered with a very clear "one solution" code. In this case, there's not clear cut code for the implementation of a solution. I wouldn't worry to much.

    – the_lotus
    Nov 27 '18 at 16:46











  • Thanks for that. I was just asking because I want to know if there's anything I should be doing to improve the quality of my questions in general.

    – G_Hosa_Phat
    Nov 27 '18 at 16:54














0












0








0








So, I'm working on a library for my internal applications that interacts with our PostgreSQL database (amongst many other things). One requirement at the moment is that this library can dump data from the database to a file. I have something working, but I've been trying to improve its performance as much as possible. This is what I'm currently looking at:



Using COPYReader As NpgsqlCopyTextReader = CType(CIADB.DBConnection.BeginTextExport(COPYSQL), NpgsqlCopyTextReader)
With COPYReader
Dim stopWatch As New Stopwatch
Dim ts As TimeSpan
Dim elapsedTime As String

' ** FIRST ATTEMPT
stopWatch.Start()
Dim BufferText As String = .ReadLine

Do While Not BufferText Is Nothing
CurrentPosition += 1
OutputFile.WriteLine(BufferText)

If Not UpdateForm Is Nothing Then
UpdateForm.UpdateProgress(Convert.ToInt32((CurrentPosition / MaxRecords) * 100))
End If

BufferText = .ReadLine
Loop

OutputFile.Flush()
OutputFile.Close()

stopWatch.Stop()
ts = stopWatch.Elapsed
elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10)

' ** FIRST ATTEMPT RESULTS
' ** Records Retrieved: 65358
' ** Time To Complete: 2:12.07
' ** Lines Written: 65358
' ** File Size: 8,166 KB

' ** SECOND ATTEMPT
stopWatch.Start()

Using TestOutputFile As New IO.StreamWriter(DestinationFile.FullName.Replace(".TXT", "_TEST.TXT"), False)
TestOutputFile.Write(.ReadToEndAsync.Result)
End Using

stopWatch.Stop()
ts = stopWatch.Elapsed
elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10)

' ** SECOND ATTEMPT
' ** Records Retrieved: 65358
' ** Time To Complete: 1:04.01
' ** Lines Written: 65358
' ** File Size: 8,102 KB
End With
End Using


I've run multiple tests of each method and come up with pretty much the same results. FIRST ATTEMPT takes about twice as long as SECOND ATTEMPT



Obviously, the UpdateForm.UpdateProgress method used in FIRST ATTEMPT (used to keep the form responsive and show the current progress of the export) is going to cause the process to take longer because of the form updating and such involved, not to mention the line-by-line writing to the file. This is pretty much exactly why I was looking at reducing the number of extra calls by doing a full dump in one line of code. The problem is that if I use the "one-liner", the form is completely unresponsive until the process is complete.



I've tried moving the code for the "all-in-one-shot" dump from the SECOND ATTEMPT into a separate Async method, but I'm extremely unfamiliar with async methods in general, so I'm (obviously) not doing it right:



Private Async Sub OutputToFile(ByVal COPYReader As NpgsqlCopyTextReader, ByVal DestinationFile As IO.FileInfo)
' ** METHOD 3
Using TestOutputFile As New IO.StreamWriter(DestinationFile.FullName.Replace(".TXT", "_TEST.TXT"), False)
Await TestOutputFile.WriteAsync(COPYReader.ReadToEndAsync.Result)
End Using

' ** METHOD 3 RESULTS
' ** Records Retrieved: 65358
' ** Time To Complete: 0:15.07
' ** Lines Written: 34
' ** File Size: 4 KB
End Sub


One other thing to mention: I tried moving all of this to a BackgroundWorker, but I was getting some strange behavior when I tried to call my UpdateForm.UpdateProgress method which caused the application to completely skip the actual dumping process. I've currently given up on trying to get this onto a separate thread, but I'm still open to other suggestions. This is actually one of the smaller tables that I'm dumping, so I'm not looking forward to what one of the bigger ones will do.



Just for the sake of completeness, here's the UpdateForm class that I've implemented in my library for reusability across other applications:



Imports System.Windows.Forms

Namespace Common
Public Class FormHandler
Implements IDisposable

Public Property ApplicationForm As Form
Public Property ApplicationStatusLabel As Label
Public Property ApplicationToolStripLabel As ToolStripStatusLabel
Public Property ApplicationProgressBar As ProgressBar

Private LabelVisibleState As Boolean = True
Private ProgressBarVisibleState As Boolean = True
Private CurrentStatusText As String
Private CurrentProgress As Integer

Public Sub New(ByVal AppForm As Form)
ApplicationForm = AppForm
End Sub

Public Sub New(ByVal StatusLabel As Label, ByVal Progress As ProgressBar)
ApplicationStatusLabel = StatusLabel
ApplicationToolStripLabel = Nothing
ApplicationProgressBar = Progress
ApplicationForm = ApplicationProgressBar.Parent.FindForm

LabelVisibleState = StatusLabel.Visible
ProgressBarVisibleState = Progress.Visible

With ApplicationProgressBar
.Minimum = 0
.Maximum = 100
.Value = 0
.Visible = True
End With

With ApplicationStatusLabel
.Visible = True
.Text = ""
End With
End Sub

Public Sub New(ByVal StatusLabel As ToolStripStatusLabel, ByVal Progress As ProgressBar)
ApplicationToolStripLabel = StatusLabel
ApplicationStatusLabel = Nothing
ApplicationProgressBar = Progress
ApplicationForm = ApplicationProgressBar.Parent.FindForm

LabelVisibleState = StatusLabel.Visible
ProgressBarVisibleState = Progress.Visible

With ApplicationProgressBar
.Minimum = 0
.Maximum = 100
.Value = 0
.Visible = True
End With

With ApplicationToolStripLabel
.Visible = True
.Text = ""
End With
End Sub

Public Sub New(ByVal AppForm As Form, ByVal StatusLabel As Label, ByVal Progress As ProgressBar)
ApplicationForm = AppForm
ApplicationStatusLabel = StatusLabel
ApplicationToolStripLabel = Nothing
ApplicationProgressBar = Progress

LabelVisibleState = StatusLabel.Visible
ProgressBarVisibleState = Progress.Visible

With ApplicationProgressBar
.Minimum = 0
.Maximum = 100
.Value = 0
.Visible = True
End With

With ApplicationStatusLabel
.Visible = True
.Text = ""
End With
End Sub

Public Sub New(ByVal AppForm As Form, ByVal StatusLabel As ToolStripStatusLabel, ByVal Progress As ProgressBar)
ApplicationForm = AppForm
ApplicationToolStripLabel = StatusLabel
ApplicationStatusLabel = Nothing
ApplicationProgressBar = Progress

LabelVisibleState = StatusLabel.Visible
ProgressBarVisibleState = Progress.Visible

With ApplicationProgressBar
.Minimum = 0
.Maximum = 100
.Value = 0
.Visible = True
End With

With ApplicationToolStripLabel
.Visible = True
.Text = ""
End With
End Sub

Friend Sub UpdateProgress(ByVal StatusText As String, ByVal CurrentPosition As Integer, ByVal MaxValue As Integer)
CurrentStatusText = StatusText
CurrentProgress = Convert.ToInt32((CurrentPosition / MaxValue) * 100)
UpdateStatus()
End Sub

Friend Sub UpdateProgress(ByVal StatusText As String, ByVal PercentComplete As Decimal)
CurrentStatusText = StatusText
CurrentProgress = Convert.ToInt32(PercentComplete)
UpdateStatus()
End Sub

Friend Sub UpdateProgress(ByVal StatusText As String)
CurrentStatusText = StatusText
CurrentProgress = 0
UpdateStatus()
End Sub

Friend Sub UpdateProgress(ByVal PercentComplete As Decimal)
CurrentProgress = Convert.ToInt32(PercentComplete)
UpdateStatus()
End Sub

Friend Sub UpdateProgress(ByVal CurrentPosition As Integer, ByVal MaxValue As Integer)
CurrentProgress = Convert.ToInt32((CurrentPosition / MaxValue) * 100)
UpdateStatus()
End Sub

Friend Sub ResetProgressUpdate()
CurrentStatusText = ""
CurrentProgress = 0
UpdateStatus()
End Sub

Private Sub UpdateStatus()
If Not ApplicationForm Is Nothing Then
If ApplicationForm.InvokeRequired Then
Dim UpdateInvoker As New MethodInvoker(AddressOf UpdateStatus)

Try
ApplicationForm.Invoke(UpdateInvoker)
Catch ex As Exception
Dim InvokeError As New ErrorHandler(ex)

InvokeError.LogException()
End Try
Else
UpdateApplicationProgress(CurrentStatusText)
End If
End If
End Sub

Friend Sub UpdateApplicationProgress(ByVal ProgressText As String)
If Not ApplicationForm Is Nothing Then
With ApplicationForm
If Not ProgressText Is Nothing Then
If Not ApplicationStatusLabel Is Nothing Then
ApplicationStatusLabel.Text = ProgressText
End If

If Not ApplicationToolStripLabel Is Nothing Then
ApplicationToolStripLabel.Text = ProgressText
End If
End If

If Not ApplicationProgressBar Is Nothing Then
ApplicationProgressBar.Value = CurrentProgress
End If
End With

ApplicationForm.Refresh()
Application.DoEvents()
End If
End Sub

Public Sub Dispose() Implements IDisposable.Dispose
If Not ApplicationForm Is Nothing Then
ApplicationForm.Dispose()
End If

If Not ApplicationStatusLabel Is Nothing Then
ApplicationStatusLabel.Visible = LabelVisibleState
ApplicationStatusLabel.Dispose()
End If

If Not ApplicationToolStripLabel Is Nothing Then
ApplicationToolStripLabel.Visible = LabelVisibleState
ApplicationToolStripLabel.Dispose()
End If

If Not ApplicationProgressBar Is Nothing Then
ApplicationProgressBar.Visible = ProgressBarVisibleState
ApplicationProgressBar.Dispose()
End If
End Sub
End Class
End Namespace




EDIT



Per the suggestion in the comments from @the_lotus, I modified my FIRST ATTEMPT slightly to check the value of the current progress (I declared a CurrentProgress variable as an Integer), and it dramatically improved the time taken:



' ** FOURTH ATTEMPT
Using COPYReader As NpgsqlCopyTextReader = CType(CIADB.DBConnection.BeginTextExport(COPYSQL), NpgsqlCopyTextReader)
With COPYReader
Dim stopWatch As New Stopwatch
Dim ts As TimeSpan
Dim elapsedTime As String
Dim CurrentProgress As Integer = 0

stopWatch.Start()
Dim BufferText As String = .ReadLine

Do While Not BufferText Is Nothing
CurrentPosition += 1
OutputFile.WriteLine(BufferText)

' ** Checks to see if the value of the ProgressBar will actually
' ** be changed by the CurrentPosition before making a call to
' ** UpdateProgress. If the value doesn't change, don't waste
' ** the call
If Convert.ToInt32((CurrentPosition / MaxRecords) * 100) <> CurrentProgress Then
CurrentProgress = Convert.ToInt32((CurrentPosition / MaxRecords) * 100)

If Not UpdateForm Is Nothing Then
UpdateForm.UpdateProgress(CurrentProgress)
End If
End If

BufferText = .ReadLine
Loop

OutputFile.Flush()
OutputFile.Close()

stopWatch.Stop()
ts = stopWatch.Elapsed
elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10)
End With
End Using
' ** FOURTH ATTEMPT RESULTS
' ** Records Retrieved: 65358
' ** Time To Complete: 0:47.45
' ** Lines Written: 65358
' ** File Size: 8,166 KB


Of course, the form is a "little" less responsive than if I were making the call on every record, but I'm thinking it's worth the trade-off.





EDIT #2



So that I could minimize the amount of code I'd have to retype (read: "copy/paste") each time I use the UpdateProgress method, I've moved the test for changed values over there and it seems to be operating with the same performance improvements. Again, for the sake of completeness, here's the code for the two private methods involved in doing the actual progress/status update:



Private Sub UpdateStatus()
If Not ApplicationForm Is Nothing Then
If ApplicationForm.InvokeRequired Then
Dim UpdateInvoker As New MethodInvoker(AddressOf UpdateStatus)

Try
ApplicationForm.Invoke(UpdateInvoker)
Catch ex As Exception
Dim InvokeError As New ErrorHandler(ex)

InvokeError.LogException()
End Try
Else
UpdateApplicationProgress()
End If
End If
End Sub

Private Sub UpdateApplicationProgress()
Dim Changed As Boolean = False

If Not ApplicationForm Is Nothing Then
With ApplicationForm
If Not CurrentStatusText Is Nothing Then
If Not ApplicationStatusLabel Is Nothing Then
If ApplicationStatusLabel.Text <> CurrentStatusText Then
Changed = True
ApplicationStatusLabel.Text = CurrentStatusText
End If
End If

If Not ApplicationToolStripLabel Is Nothing Then
If ApplicationToolStripLabel.Text <> CurrentStatusText Then
Changed = True
ApplicationToolStripLabel.Text = CurrentStatusText
End If
End If
End If

If Not ApplicationProgressBar Is Nothing Then
If ApplicationProgressBar.Value <> CurrentProgress Then
Changed = True
ApplicationProgressBar.Value = CurrentProgress
End If
End If
End With

If Changed Then
ApplicationForm.Refresh()
End If

Application.DoEvents()
End If
End Sub


Doing it this way also came with the added benefit of returning some of the responsiveness to the form that was previously lost. I hope at least some of this code and information is helpful to someone out there.










share|improve this question
















So, I'm working on a library for my internal applications that interacts with our PostgreSQL database (amongst many other things). One requirement at the moment is that this library can dump data from the database to a file. I have something working, but I've been trying to improve its performance as much as possible. This is what I'm currently looking at:



Using COPYReader As NpgsqlCopyTextReader = CType(CIADB.DBConnection.BeginTextExport(COPYSQL), NpgsqlCopyTextReader)
With COPYReader
Dim stopWatch As New Stopwatch
Dim ts As TimeSpan
Dim elapsedTime As String

' ** FIRST ATTEMPT
stopWatch.Start()
Dim BufferText As String = .ReadLine

Do While Not BufferText Is Nothing
CurrentPosition += 1
OutputFile.WriteLine(BufferText)

If Not UpdateForm Is Nothing Then
UpdateForm.UpdateProgress(Convert.ToInt32((CurrentPosition / MaxRecords) * 100))
End If

BufferText = .ReadLine
Loop

OutputFile.Flush()
OutputFile.Close()

stopWatch.Stop()
ts = stopWatch.Elapsed
elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10)

' ** FIRST ATTEMPT RESULTS
' ** Records Retrieved: 65358
' ** Time To Complete: 2:12.07
' ** Lines Written: 65358
' ** File Size: 8,166 KB

' ** SECOND ATTEMPT
stopWatch.Start()

Using TestOutputFile As New IO.StreamWriter(DestinationFile.FullName.Replace(".TXT", "_TEST.TXT"), False)
TestOutputFile.Write(.ReadToEndAsync.Result)
End Using

stopWatch.Stop()
ts = stopWatch.Elapsed
elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10)

' ** SECOND ATTEMPT
' ** Records Retrieved: 65358
' ** Time To Complete: 1:04.01
' ** Lines Written: 65358
' ** File Size: 8,102 KB
End With
End Using


I've run multiple tests of each method and come up with pretty much the same results. FIRST ATTEMPT takes about twice as long as SECOND ATTEMPT



Obviously, the UpdateForm.UpdateProgress method used in FIRST ATTEMPT (used to keep the form responsive and show the current progress of the export) is going to cause the process to take longer because of the form updating and such involved, not to mention the line-by-line writing to the file. This is pretty much exactly why I was looking at reducing the number of extra calls by doing a full dump in one line of code. The problem is that if I use the "one-liner", the form is completely unresponsive until the process is complete.



I've tried moving the code for the "all-in-one-shot" dump from the SECOND ATTEMPT into a separate Async method, but I'm extremely unfamiliar with async methods in general, so I'm (obviously) not doing it right:



Private Async Sub OutputToFile(ByVal COPYReader As NpgsqlCopyTextReader, ByVal DestinationFile As IO.FileInfo)
' ** METHOD 3
Using TestOutputFile As New IO.StreamWriter(DestinationFile.FullName.Replace(".TXT", "_TEST.TXT"), False)
Await TestOutputFile.WriteAsync(COPYReader.ReadToEndAsync.Result)
End Using

' ** METHOD 3 RESULTS
' ** Records Retrieved: 65358
' ** Time To Complete: 0:15.07
' ** Lines Written: 34
' ** File Size: 4 KB
End Sub


One other thing to mention: I tried moving all of this to a BackgroundWorker, but I was getting some strange behavior when I tried to call my UpdateForm.UpdateProgress method which caused the application to completely skip the actual dumping process. I've currently given up on trying to get this onto a separate thread, but I'm still open to other suggestions. This is actually one of the smaller tables that I'm dumping, so I'm not looking forward to what one of the bigger ones will do.



Just for the sake of completeness, here's the UpdateForm class that I've implemented in my library for reusability across other applications:



Imports System.Windows.Forms

Namespace Common
Public Class FormHandler
Implements IDisposable

Public Property ApplicationForm As Form
Public Property ApplicationStatusLabel As Label
Public Property ApplicationToolStripLabel As ToolStripStatusLabel
Public Property ApplicationProgressBar As ProgressBar

Private LabelVisibleState As Boolean = True
Private ProgressBarVisibleState As Boolean = True
Private CurrentStatusText As String
Private CurrentProgress As Integer

Public Sub New(ByVal AppForm As Form)
ApplicationForm = AppForm
End Sub

Public Sub New(ByVal StatusLabel As Label, ByVal Progress As ProgressBar)
ApplicationStatusLabel = StatusLabel
ApplicationToolStripLabel = Nothing
ApplicationProgressBar = Progress
ApplicationForm = ApplicationProgressBar.Parent.FindForm

LabelVisibleState = StatusLabel.Visible
ProgressBarVisibleState = Progress.Visible

With ApplicationProgressBar
.Minimum = 0
.Maximum = 100
.Value = 0
.Visible = True
End With

With ApplicationStatusLabel
.Visible = True
.Text = ""
End With
End Sub

Public Sub New(ByVal StatusLabel As ToolStripStatusLabel, ByVal Progress As ProgressBar)
ApplicationToolStripLabel = StatusLabel
ApplicationStatusLabel = Nothing
ApplicationProgressBar = Progress
ApplicationForm = ApplicationProgressBar.Parent.FindForm

LabelVisibleState = StatusLabel.Visible
ProgressBarVisibleState = Progress.Visible

With ApplicationProgressBar
.Minimum = 0
.Maximum = 100
.Value = 0
.Visible = True
End With

With ApplicationToolStripLabel
.Visible = True
.Text = ""
End With
End Sub

Public Sub New(ByVal AppForm As Form, ByVal StatusLabel As Label, ByVal Progress As ProgressBar)
ApplicationForm = AppForm
ApplicationStatusLabel = StatusLabel
ApplicationToolStripLabel = Nothing
ApplicationProgressBar = Progress

LabelVisibleState = StatusLabel.Visible
ProgressBarVisibleState = Progress.Visible

With ApplicationProgressBar
.Minimum = 0
.Maximum = 100
.Value = 0
.Visible = True
End With

With ApplicationStatusLabel
.Visible = True
.Text = ""
End With
End Sub

Public Sub New(ByVal AppForm As Form, ByVal StatusLabel As ToolStripStatusLabel, ByVal Progress As ProgressBar)
ApplicationForm = AppForm
ApplicationToolStripLabel = StatusLabel
ApplicationStatusLabel = Nothing
ApplicationProgressBar = Progress

LabelVisibleState = StatusLabel.Visible
ProgressBarVisibleState = Progress.Visible

With ApplicationProgressBar
.Minimum = 0
.Maximum = 100
.Value = 0
.Visible = True
End With

With ApplicationToolStripLabel
.Visible = True
.Text = ""
End With
End Sub

Friend Sub UpdateProgress(ByVal StatusText As String, ByVal CurrentPosition As Integer, ByVal MaxValue As Integer)
CurrentStatusText = StatusText
CurrentProgress = Convert.ToInt32((CurrentPosition / MaxValue) * 100)
UpdateStatus()
End Sub

Friend Sub UpdateProgress(ByVal StatusText As String, ByVal PercentComplete As Decimal)
CurrentStatusText = StatusText
CurrentProgress = Convert.ToInt32(PercentComplete)
UpdateStatus()
End Sub

Friend Sub UpdateProgress(ByVal StatusText As String)
CurrentStatusText = StatusText
CurrentProgress = 0
UpdateStatus()
End Sub

Friend Sub UpdateProgress(ByVal PercentComplete As Decimal)
CurrentProgress = Convert.ToInt32(PercentComplete)
UpdateStatus()
End Sub

Friend Sub UpdateProgress(ByVal CurrentPosition As Integer, ByVal MaxValue As Integer)
CurrentProgress = Convert.ToInt32((CurrentPosition / MaxValue) * 100)
UpdateStatus()
End Sub

Friend Sub ResetProgressUpdate()
CurrentStatusText = ""
CurrentProgress = 0
UpdateStatus()
End Sub

Private Sub UpdateStatus()
If Not ApplicationForm Is Nothing Then
If ApplicationForm.InvokeRequired Then
Dim UpdateInvoker As New MethodInvoker(AddressOf UpdateStatus)

Try
ApplicationForm.Invoke(UpdateInvoker)
Catch ex As Exception
Dim InvokeError As New ErrorHandler(ex)

InvokeError.LogException()
End Try
Else
UpdateApplicationProgress(CurrentStatusText)
End If
End If
End Sub

Friend Sub UpdateApplicationProgress(ByVal ProgressText As String)
If Not ApplicationForm Is Nothing Then
With ApplicationForm
If Not ProgressText Is Nothing Then
If Not ApplicationStatusLabel Is Nothing Then
ApplicationStatusLabel.Text = ProgressText
End If

If Not ApplicationToolStripLabel Is Nothing Then
ApplicationToolStripLabel.Text = ProgressText
End If
End If

If Not ApplicationProgressBar Is Nothing Then
ApplicationProgressBar.Value = CurrentProgress
End If
End With

ApplicationForm.Refresh()
Application.DoEvents()
End If
End Sub

Public Sub Dispose() Implements IDisposable.Dispose
If Not ApplicationForm Is Nothing Then
ApplicationForm.Dispose()
End If

If Not ApplicationStatusLabel Is Nothing Then
ApplicationStatusLabel.Visible = LabelVisibleState
ApplicationStatusLabel.Dispose()
End If

If Not ApplicationToolStripLabel Is Nothing Then
ApplicationToolStripLabel.Visible = LabelVisibleState
ApplicationToolStripLabel.Dispose()
End If

If Not ApplicationProgressBar Is Nothing Then
ApplicationProgressBar.Visible = ProgressBarVisibleState
ApplicationProgressBar.Dispose()
End If
End Sub
End Class
End Namespace




EDIT



Per the suggestion in the comments from @the_lotus, I modified my FIRST ATTEMPT slightly to check the value of the current progress (I declared a CurrentProgress variable as an Integer), and it dramatically improved the time taken:



' ** FOURTH ATTEMPT
Using COPYReader As NpgsqlCopyTextReader = CType(CIADB.DBConnection.BeginTextExport(COPYSQL), NpgsqlCopyTextReader)
With COPYReader
Dim stopWatch As New Stopwatch
Dim ts As TimeSpan
Dim elapsedTime As String
Dim CurrentProgress As Integer = 0

stopWatch.Start()
Dim BufferText As String = .ReadLine

Do While Not BufferText Is Nothing
CurrentPosition += 1
OutputFile.WriteLine(BufferText)

' ** Checks to see if the value of the ProgressBar will actually
' ** be changed by the CurrentPosition before making a call to
' ** UpdateProgress. If the value doesn't change, don't waste
' ** the call
If Convert.ToInt32((CurrentPosition / MaxRecords) * 100) <> CurrentProgress Then
CurrentProgress = Convert.ToInt32((CurrentPosition / MaxRecords) * 100)

If Not UpdateForm Is Nothing Then
UpdateForm.UpdateProgress(CurrentProgress)
End If
End If

BufferText = .ReadLine
Loop

OutputFile.Flush()
OutputFile.Close()

stopWatch.Stop()
ts = stopWatch.Elapsed
elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10)
End With
End Using
' ** FOURTH ATTEMPT RESULTS
' ** Records Retrieved: 65358
' ** Time To Complete: 0:47.45
' ** Lines Written: 65358
' ** File Size: 8,166 KB


Of course, the form is a "little" less responsive than if I were making the call on every record, but I'm thinking it's worth the trade-off.





EDIT #2



So that I could minimize the amount of code I'd have to retype (read: "copy/paste") each time I use the UpdateProgress method, I've moved the test for changed values over there and it seems to be operating with the same performance improvements. Again, for the sake of completeness, here's the code for the two private methods involved in doing the actual progress/status update:



Private Sub UpdateStatus()
If Not ApplicationForm Is Nothing Then
If ApplicationForm.InvokeRequired Then
Dim UpdateInvoker As New MethodInvoker(AddressOf UpdateStatus)

Try
ApplicationForm.Invoke(UpdateInvoker)
Catch ex As Exception
Dim InvokeError As New ErrorHandler(ex)

InvokeError.LogException()
End Try
Else
UpdateApplicationProgress()
End If
End If
End Sub

Private Sub UpdateApplicationProgress()
Dim Changed As Boolean = False

If Not ApplicationForm Is Nothing Then
With ApplicationForm
If Not CurrentStatusText Is Nothing Then
If Not ApplicationStatusLabel Is Nothing Then
If ApplicationStatusLabel.Text <> CurrentStatusText Then
Changed = True
ApplicationStatusLabel.Text = CurrentStatusText
End If
End If

If Not ApplicationToolStripLabel Is Nothing Then
If ApplicationToolStripLabel.Text <> CurrentStatusText Then
Changed = True
ApplicationToolStripLabel.Text = CurrentStatusText
End If
End If
End If

If Not ApplicationProgressBar Is Nothing Then
If ApplicationProgressBar.Value <> CurrentProgress Then
Changed = True
ApplicationProgressBar.Value = CurrentProgress
End If
End If
End With

If Changed Then
ApplicationForm.Refresh()
End If

Application.DoEvents()
End If
End Sub


Doing it this way also came with the added benefit of returning some of the responsiveness to the form that was previously lost. I hope at least some of this code and information is helpful to someone out there.







vb.net npgsql






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 21 '18 at 19:46







G_Hosa_Phat

















asked Nov 21 '18 at 18:05









G_Hosa_PhatG_Hosa_Phat

280418




280418








  • 2





    Your second attempt might not even go to the database since it could be cached. Also, don't call UpdateProgress on each call. It's not necessary when the percentage didn't even move.

    – the_lotus
    Nov 21 '18 at 18:11






  • 1





    @the_lotus - HOLY CRAP! I added a small bit of code to check whether or not the current progress percentage has changed (see edit) before calling UpdateProgress, and it reduced the amount of time dramatically - down to 0:47:45! What a simple but significant thing to overlook! Thanks for that!

    – G_Hosa_Phat
    Nov 21 '18 at 18:20











  • Can someone please clarify why the downvote and vote to close as "opinion-based"? It is my intent to ask "good" questions and I attempt to provide clear examples of my attempts to answer/resolve the issues on my own so as not to add to the clutter of "poor" questions.

    – G_Hosa_Phat
    Nov 27 '18 at 16:38






  • 1





    Some people want stackoverflow to be a place for questions that can be answered with a very clear "one solution" code. In this case, there's not clear cut code for the implementation of a solution. I wouldn't worry to much.

    – the_lotus
    Nov 27 '18 at 16:46











  • Thanks for that. I was just asking because I want to know if there's anything I should be doing to improve the quality of my questions in general.

    – G_Hosa_Phat
    Nov 27 '18 at 16:54














  • 2





    Your second attempt might not even go to the database since it could be cached. Also, don't call UpdateProgress on each call. It's not necessary when the percentage didn't even move.

    – the_lotus
    Nov 21 '18 at 18:11






  • 1





    @the_lotus - HOLY CRAP! I added a small bit of code to check whether or not the current progress percentage has changed (see edit) before calling UpdateProgress, and it reduced the amount of time dramatically - down to 0:47:45! What a simple but significant thing to overlook! Thanks for that!

    – G_Hosa_Phat
    Nov 21 '18 at 18:20











  • Can someone please clarify why the downvote and vote to close as "opinion-based"? It is my intent to ask "good" questions and I attempt to provide clear examples of my attempts to answer/resolve the issues on my own so as not to add to the clutter of "poor" questions.

    – G_Hosa_Phat
    Nov 27 '18 at 16:38






  • 1





    Some people want stackoverflow to be a place for questions that can be answered with a very clear "one solution" code. In this case, there's not clear cut code for the implementation of a solution. I wouldn't worry to much.

    – the_lotus
    Nov 27 '18 at 16:46











  • Thanks for that. I was just asking because I want to know if there's anything I should be doing to improve the quality of my questions in general.

    – G_Hosa_Phat
    Nov 27 '18 at 16:54








2




2





Your second attempt might not even go to the database since it could be cached. Also, don't call UpdateProgress on each call. It's not necessary when the percentage didn't even move.

– the_lotus
Nov 21 '18 at 18:11





Your second attempt might not even go to the database since it could be cached. Also, don't call UpdateProgress on each call. It's not necessary when the percentage didn't even move.

– the_lotus
Nov 21 '18 at 18:11




1




1





@the_lotus - HOLY CRAP! I added a small bit of code to check whether or not the current progress percentage has changed (see edit) before calling UpdateProgress, and it reduced the amount of time dramatically - down to 0:47:45! What a simple but significant thing to overlook! Thanks for that!

– G_Hosa_Phat
Nov 21 '18 at 18:20





@the_lotus - HOLY CRAP! I added a small bit of code to check whether or not the current progress percentage has changed (see edit) before calling UpdateProgress, and it reduced the amount of time dramatically - down to 0:47:45! What a simple but significant thing to overlook! Thanks for that!

– G_Hosa_Phat
Nov 21 '18 at 18:20













Can someone please clarify why the downvote and vote to close as "opinion-based"? It is my intent to ask "good" questions and I attempt to provide clear examples of my attempts to answer/resolve the issues on my own so as not to add to the clutter of "poor" questions.

– G_Hosa_Phat
Nov 27 '18 at 16:38





Can someone please clarify why the downvote and vote to close as "opinion-based"? It is my intent to ask "good" questions and I attempt to provide clear examples of my attempts to answer/resolve the issues on my own so as not to add to the clutter of "poor" questions.

– G_Hosa_Phat
Nov 27 '18 at 16:38




1




1





Some people want stackoverflow to be a place for questions that can be answered with a very clear "one solution" code. In this case, there's not clear cut code for the implementation of a solution. I wouldn't worry to much.

– the_lotus
Nov 27 '18 at 16:46





Some people want stackoverflow to be a place for questions that can be answered with a very clear "one solution" code. In this case, there's not clear cut code for the implementation of a solution. I wouldn't worry to much.

– the_lotus
Nov 27 '18 at 16:46













Thanks for that. I was just asking because I want to know if there's anything I should be doing to improve the quality of my questions in general.

– G_Hosa_Phat
Nov 27 '18 at 16:54





Thanks for that. I was just asking because I want to know if there's anything I should be doing to improve the quality of my questions in general.

– G_Hosa_Phat
Nov 27 '18 at 16:54












1 Answer
1






active

oldest

votes


















1














You don't need to call UpdateProgress on each call. It's not necessary when the percentage didn't even move. Try to do a small check and only update the percentage when needed.



It's also possible that the second attempt is faster because it doesn't go to the database. The data could be cached.






share|improve this answer
























  • SO MUCH THIS! The completion time improved by about 200% down to approximately 45 seconds. While the form is a bit less responsive because it isn't being updated as frequently, it's still responsive enough that I can work with it and the trade-off is well worth the difference in my opinion. I still find it kinda funny that the file sizes are different, but that's a question for another day.

    – G_Hosa_Phat
    Nov 21 '18 at 18:43






  • 3





    @G_Hosa_Phat I suggest you still take the time to look at background worker. There's a way in it to send progress back to the form.

    – the_lotus
    Nov 21 '18 at 18:53











  • I've tried throwing the process into a BackgroundWorker, but when it would make a call to my UpdateProgress method, it would (apparently) throw an exception during the Invoke method that I couldn't trap. I tried wrapping that Invoke method in a Try...Catch block, same with the UpdateProgress method, and even the entire code block, but the Invoke call just "jumped" out of the executing code block completely and left my application looping indefinitely waiting for the BackgroundWorker to "complete".

    – G_Hosa_Phat
    Nov 21 '18 at 19:22








  • 2





    @G_Hosa_Phat with backgroundwork, don't use your UpdateProgress method. Look at the doc they have an example of how to use ReportProgress and your form handle the ProgressChanged event.

    – the_lotus
    Nov 21 '18 at 19:26











  • Yeah, I wish I still had the code to show, but that was several iterations ago and since I gave up on that method, I deleted all of that code. I may go back and take a look at it again later, but this method seems to be working well enough for now. Thanks for the tip and the links. When I have some "free time" to rebuild this later, I'll certainly take a look.

    – G_Hosa_Phat
    Nov 21 '18 at 19:35












Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53418109%2flong-running-process-with-responsive-form-performance-improvements%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














You don't need to call UpdateProgress on each call. It's not necessary when the percentage didn't even move. Try to do a small check and only update the percentage when needed.



It's also possible that the second attempt is faster because it doesn't go to the database. The data could be cached.






share|improve this answer
























  • SO MUCH THIS! The completion time improved by about 200% down to approximately 45 seconds. While the form is a bit less responsive because it isn't being updated as frequently, it's still responsive enough that I can work with it and the trade-off is well worth the difference in my opinion. I still find it kinda funny that the file sizes are different, but that's a question for another day.

    – G_Hosa_Phat
    Nov 21 '18 at 18:43






  • 3





    @G_Hosa_Phat I suggest you still take the time to look at background worker. There's a way in it to send progress back to the form.

    – the_lotus
    Nov 21 '18 at 18:53











  • I've tried throwing the process into a BackgroundWorker, but when it would make a call to my UpdateProgress method, it would (apparently) throw an exception during the Invoke method that I couldn't trap. I tried wrapping that Invoke method in a Try...Catch block, same with the UpdateProgress method, and even the entire code block, but the Invoke call just "jumped" out of the executing code block completely and left my application looping indefinitely waiting for the BackgroundWorker to "complete".

    – G_Hosa_Phat
    Nov 21 '18 at 19:22








  • 2





    @G_Hosa_Phat with backgroundwork, don't use your UpdateProgress method. Look at the doc they have an example of how to use ReportProgress and your form handle the ProgressChanged event.

    – the_lotus
    Nov 21 '18 at 19:26











  • Yeah, I wish I still had the code to show, but that was several iterations ago and since I gave up on that method, I deleted all of that code. I may go back and take a look at it again later, but this method seems to be working well enough for now. Thanks for the tip and the links. When I have some "free time" to rebuild this later, I'll certainly take a look.

    – G_Hosa_Phat
    Nov 21 '18 at 19:35
















1














You don't need to call UpdateProgress on each call. It's not necessary when the percentage didn't even move. Try to do a small check and only update the percentage when needed.



It's also possible that the second attempt is faster because it doesn't go to the database. The data could be cached.






share|improve this answer
























  • SO MUCH THIS! The completion time improved by about 200% down to approximately 45 seconds. While the form is a bit less responsive because it isn't being updated as frequently, it's still responsive enough that I can work with it and the trade-off is well worth the difference in my opinion. I still find it kinda funny that the file sizes are different, but that's a question for another day.

    – G_Hosa_Phat
    Nov 21 '18 at 18:43






  • 3





    @G_Hosa_Phat I suggest you still take the time to look at background worker. There's a way in it to send progress back to the form.

    – the_lotus
    Nov 21 '18 at 18:53











  • I've tried throwing the process into a BackgroundWorker, but when it would make a call to my UpdateProgress method, it would (apparently) throw an exception during the Invoke method that I couldn't trap. I tried wrapping that Invoke method in a Try...Catch block, same with the UpdateProgress method, and even the entire code block, but the Invoke call just "jumped" out of the executing code block completely and left my application looping indefinitely waiting for the BackgroundWorker to "complete".

    – G_Hosa_Phat
    Nov 21 '18 at 19:22








  • 2





    @G_Hosa_Phat with backgroundwork, don't use your UpdateProgress method. Look at the doc they have an example of how to use ReportProgress and your form handle the ProgressChanged event.

    – the_lotus
    Nov 21 '18 at 19:26











  • Yeah, I wish I still had the code to show, but that was several iterations ago and since I gave up on that method, I deleted all of that code. I may go back and take a look at it again later, but this method seems to be working well enough for now. Thanks for the tip and the links. When I have some "free time" to rebuild this later, I'll certainly take a look.

    – G_Hosa_Phat
    Nov 21 '18 at 19:35














1












1








1







You don't need to call UpdateProgress on each call. It's not necessary when the percentage didn't even move. Try to do a small check and only update the percentage when needed.



It's also possible that the second attempt is faster because it doesn't go to the database. The data could be cached.






share|improve this answer













You don't need to call UpdateProgress on each call. It's not necessary when the percentage didn't even move. Try to do a small check and only update the percentage when needed.



It's also possible that the second attempt is faster because it doesn't go to the database. The data could be cached.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 21 '18 at 18:34









the_lotusthe_lotus

10.2k12346




10.2k12346













  • SO MUCH THIS! The completion time improved by about 200% down to approximately 45 seconds. While the form is a bit less responsive because it isn't being updated as frequently, it's still responsive enough that I can work with it and the trade-off is well worth the difference in my opinion. I still find it kinda funny that the file sizes are different, but that's a question for another day.

    – G_Hosa_Phat
    Nov 21 '18 at 18:43






  • 3





    @G_Hosa_Phat I suggest you still take the time to look at background worker. There's a way in it to send progress back to the form.

    – the_lotus
    Nov 21 '18 at 18:53











  • I've tried throwing the process into a BackgroundWorker, but when it would make a call to my UpdateProgress method, it would (apparently) throw an exception during the Invoke method that I couldn't trap. I tried wrapping that Invoke method in a Try...Catch block, same with the UpdateProgress method, and even the entire code block, but the Invoke call just "jumped" out of the executing code block completely and left my application looping indefinitely waiting for the BackgroundWorker to "complete".

    – G_Hosa_Phat
    Nov 21 '18 at 19:22








  • 2





    @G_Hosa_Phat with backgroundwork, don't use your UpdateProgress method. Look at the doc they have an example of how to use ReportProgress and your form handle the ProgressChanged event.

    – the_lotus
    Nov 21 '18 at 19:26











  • Yeah, I wish I still had the code to show, but that was several iterations ago and since I gave up on that method, I deleted all of that code. I may go back and take a look at it again later, but this method seems to be working well enough for now. Thanks for the tip and the links. When I have some "free time" to rebuild this later, I'll certainly take a look.

    – G_Hosa_Phat
    Nov 21 '18 at 19:35



















  • SO MUCH THIS! The completion time improved by about 200% down to approximately 45 seconds. While the form is a bit less responsive because it isn't being updated as frequently, it's still responsive enough that I can work with it and the trade-off is well worth the difference in my opinion. I still find it kinda funny that the file sizes are different, but that's a question for another day.

    – G_Hosa_Phat
    Nov 21 '18 at 18:43






  • 3





    @G_Hosa_Phat I suggest you still take the time to look at background worker. There's a way in it to send progress back to the form.

    – the_lotus
    Nov 21 '18 at 18:53











  • I've tried throwing the process into a BackgroundWorker, but when it would make a call to my UpdateProgress method, it would (apparently) throw an exception during the Invoke method that I couldn't trap. I tried wrapping that Invoke method in a Try...Catch block, same with the UpdateProgress method, and even the entire code block, but the Invoke call just "jumped" out of the executing code block completely and left my application looping indefinitely waiting for the BackgroundWorker to "complete".

    – G_Hosa_Phat
    Nov 21 '18 at 19:22








  • 2





    @G_Hosa_Phat with backgroundwork, don't use your UpdateProgress method. Look at the doc they have an example of how to use ReportProgress and your form handle the ProgressChanged event.

    – the_lotus
    Nov 21 '18 at 19:26











  • Yeah, I wish I still had the code to show, but that was several iterations ago and since I gave up on that method, I deleted all of that code. I may go back and take a look at it again later, but this method seems to be working well enough for now. Thanks for the tip and the links. When I have some "free time" to rebuild this later, I'll certainly take a look.

    – G_Hosa_Phat
    Nov 21 '18 at 19:35

















SO MUCH THIS! The completion time improved by about 200% down to approximately 45 seconds. While the form is a bit less responsive because it isn't being updated as frequently, it's still responsive enough that I can work with it and the trade-off is well worth the difference in my opinion. I still find it kinda funny that the file sizes are different, but that's a question for another day.

– G_Hosa_Phat
Nov 21 '18 at 18:43





SO MUCH THIS! The completion time improved by about 200% down to approximately 45 seconds. While the form is a bit less responsive because it isn't being updated as frequently, it's still responsive enough that I can work with it and the trade-off is well worth the difference in my opinion. I still find it kinda funny that the file sizes are different, but that's a question for another day.

– G_Hosa_Phat
Nov 21 '18 at 18:43




3




3





@G_Hosa_Phat I suggest you still take the time to look at background worker. There's a way in it to send progress back to the form.

– the_lotus
Nov 21 '18 at 18:53





@G_Hosa_Phat I suggest you still take the time to look at background worker. There's a way in it to send progress back to the form.

– the_lotus
Nov 21 '18 at 18:53













I've tried throwing the process into a BackgroundWorker, but when it would make a call to my UpdateProgress method, it would (apparently) throw an exception during the Invoke method that I couldn't trap. I tried wrapping that Invoke method in a Try...Catch block, same with the UpdateProgress method, and even the entire code block, but the Invoke call just "jumped" out of the executing code block completely and left my application looping indefinitely waiting for the BackgroundWorker to "complete".

– G_Hosa_Phat
Nov 21 '18 at 19:22







I've tried throwing the process into a BackgroundWorker, but when it would make a call to my UpdateProgress method, it would (apparently) throw an exception during the Invoke method that I couldn't trap. I tried wrapping that Invoke method in a Try...Catch block, same with the UpdateProgress method, and even the entire code block, but the Invoke call just "jumped" out of the executing code block completely and left my application looping indefinitely waiting for the BackgroundWorker to "complete".

– G_Hosa_Phat
Nov 21 '18 at 19:22






2




2





@G_Hosa_Phat with backgroundwork, don't use your UpdateProgress method. Look at the doc they have an example of how to use ReportProgress and your form handle the ProgressChanged event.

– the_lotus
Nov 21 '18 at 19:26





@G_Hosa_Phat with backgroundwork, don't use your UpdateProgress method. Look at the doc they have an example of how to use ReportProgress and your form handle the ProgressChanged event.

– the_lotus
Nov 21 '18 at 19:26













Yeah, I wish I still had the code to show, but that was several iterations ago and since I gave up on that method, I deleted all of that code. I may go back and take a look at it again later, but this method seems to be working well enough for now. Thanks for the tip and the links. When I have some "free time" to rebuild this later, I'll certainly take a look.

– G_Hosa_Phat
Nov 21 '18 at 19:35





Yeah, I wish I still had the code to show, but that was several iterations ago and since I gave up on that method, I deleted all of that code. I may go back and take a look at it again later, but this method seems to be working well enough for now. Thanks for the tip and the links. When I have some "free time" to rebuild this later, I'll certainly take a look.

– G_Hosa_Phat
Nov 21 '18 at 19:35




















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53418109%2flong-running-process-with-responsive-form-performance-improvements%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Guess what letter conforming each word

Port of Spain

Run scheduled task as local user group (not BUILTIN)