|
-
Jan 9th, 2009, 05:02 PM
#1
Thread Starter
Lively Member
[RESOLVED] Different Performance, EXE vs. Uncompiled Code
I have a project I've been using for a few years now.
Because part of it has semi-frequent need to change, for years I have just opened the project and clicked the "Run" button.
In the Public Sub Main(), it opens a database connection and then the front form is made visible by Front_Form.Show.
The Front_Form has some buttons on it and I click one of them to select which portion of the App I want to run.
The Front_Form closes and the the selected form opens.
In the selected form, there is a Private Sub Form_Load () which did enable buttons and provided initial values for the various text boxes.
Clicking the Start Button launched the main part of the code.
The text boxes update as progress continues to its end. As a side note, I learned early off that I have to put a .01 sec pause timer in the code at various places, or the text boxes never update (even though the actual code is running).
When complete, there was one final Message Box to alert me the app has successfully finished.
Clicking OK closed the form and ended the code.
As I say, except for the times I've had to re-write the processing section, it has worked fine since early 2006.
The processing section reads dynamic data from disparate sources, and the source code for how that public info is presented has occasion to change on average once a month or so. As a result, I have opted to just run the uncompiled code instead of creating a executable for it.
However, I have need to leave for a couple of weeks, and will not be able to manually run the code.
So I need to compile it such that simply opening it will launch it.
1. I scrapped the front form which required a button click
2. I coded the Public Sub Main() to show the actual form I want.
3. I coded the form to start the actual code running in the Front form's "Form_Load()" sub.
4. I removed the message box at the End.
The problem is that the code runs, but the form is never visible.
Here is the Public Sub Main() code:
Code:
Public Sub Main()
Set adoConnection = New ADODB.Connection
adoConnection.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source= " & "C:\Database\Data_Main.mdb;"
adoConnection.Open
Data_Form.Show
End Sub
Here is the Private Sub Form_Load() code:
Code:
Private Sub Form_Load()
a_PauseTime = Delay_Time.Text ' Set duration.
a_Start = Timer ' Set start time.
Do While Timer < a_Start + a_PauseTime ‘pauses for .01 second
DoEvents
Loop
Status_Box.Text = "Waiting for user inputs..."
a_Start = Timer ' Set start time.
Do While Timer < a_Start + (a_PauseTime * 500) ‘pauses for 5 seconds
DoEvents
Loop
Stage_1 ‘launches main part of code
End Sub
As I mentioned, the body of the code is running, and seems to be running correctly.
The only problem is that the form is not visible so I cannot view its progress.
A side note is that the app form is not even visible on the task bar, but I can see it in Task Manager.
Please help!
I believe it is probably something simple which I just am not knowledgeable about.
-
Jan 9th, 2009, 05:21 PM
#2
Fanatic Member
Re: Different Performance, EXE vs. Uncompiled Code
I don't know if this has anything to do with your problem but
is not a comment. Try using ' (ascii 34).
`=ascii 96
-
Jan 9th, 2009, 05:32 PM
#3
Re: Different Performance, EXE vs. Uncompiled Code
The first few things that I see are:
- Public Sub Main? Main isn't supposed to be Public. Why would you want to call it from some other module??
- In general it's bad form to keep a database connection open when you aren't using it, i.e. for the life of the program.
- A Form cannot Show until after Form_Load completes (or explcitly calls Me.Show). Why are these weird DoEvents() loops in Form_Load?
- Form_Load calls "Stage_1." It looks as if you are trying to treat this Form as a place for synchonous processing.
Most of these points don't matter. I think your trouble spot is that you may be trying to run the whole program during Form_Load, or perhaps a large part of it.
As much of the time as possible the logic in a VB6 program compiled for the Windows subsystem (and without special care this is always what you have) none of your code should be executing. Instead the program should be sitting in the (invisible) message loop awaiting a window message such as an event. Only when such events are dispatched to your handler routines should you have running code, and then only for a small amount of processing.
When you have substantial "crunching" to do, you need some way to drive the process by causing events.
In the case of database access you can often use ADO objects with async method calls that raise events as each action (Execute, etc.) completes.
If you have non-database logic that might be loop driven in a batch or Console subsystem program, the easiest alternative is to unroll the loop and drive iteration via a Timer control. In the Timer event handler you perform some quantum of work, such as processing 100 records. Then you fall out and await the next Timer event to process the next 100 records, etc. When complete you can disable the Timer to prevent further quantum events.
You can safely set the Timer's Interval property to a 1 ms. value (the minimum) to ensure that you are not adding excessive artificial delays.
Almost any time you find yourself calling the DoEvents() function it is a sign that you've broken the VB Form paradigm.
-
Jan 9th, 2009, 05:34 PM
#4
Fanatic Member
Re: Different Performance, EXE vs. Uncompiled Code
Does a_PauseTime have the text of "0.01" ? I'm asking because Timer gives the time in seconds while the API function timeGetTime or a timer control give the time in milliseconds hopefully you haven't made the wrong assumption. Since I can't see the value of PauseTime, I have to ask.
-
Jan 9th, 2009, 05:37 PM
#5
Re: Different Performance, EXE vs. Uncompiled Code
How about trying to show it modally?
Code:
Data_Form.Show vbModal
-
Jan 9th, 2009, 05:39 PM
#6
Re: Different Performance, EXE vs. Uncompiled Code
Another option is to rewrite the program as a batch process with no Form in it at all. This could spawn a second program with Forms upon completion, to display results or errors.
Doing this almost requires linking the first program for the Console subsystem though. VB6 cannot do this unaided.
-
Jan 9th, 2009, 05:58 PM
#7
Thread Starter
Lively Member
Re: Different Performance, EXE vs. Uncompiled Code
I don't know if this has anything to do with your problem but
is not a comment. Try using ' (ascii 34).
`=ascii 96
Yeah, I know. I'm not sure why my post editor used that character. I hit the same key, but with Calibri font, i guess it typed that character.
-
Jan 9th, 2009, 07:36 PM
#8
Thread Starter
Lively Member
Re: Different Performance, EXE vs. Uncompiled Code
- Public Sub Main? Main isn't supposed to be Public. Why would you want to call it from some other module??
It doesn't get called from any modules. Everything else in that module is called from other modules, and are Public, so I probably just assumed it should be too.
Does it hurt anything? - In general it's bad form to keep a database connection open when you aren't using it, i.e. for the life of the program.
All portions of the program use the database non-stop until the program completes. - A Form cannot Show until after Form_Load completes (or explicitly calls Me.Show).
Hmmm, I bet you've hit the issue right here.
I can easily run a test of this shortly and let you know.
I did try to move "Data_Form.Show" from Main to Form_Load, but got an error so I moved it back. I've certainly seen ME. used in VBA for Access to refer to the current form. I assume that is also supported in VB6 since you suggest it. Would "Me.Show" have any net difference in performance from "Data_Form.Show"? - Why are these weird DoEvents() loops in Form_Load?
Well, the first one I don't remember why it is there.
I am certain the second one was needed to provide time for the form to show the updated values for the text boxes.
I found that the code was simply running too fast and I needed to slow it down.
That may be indicative of some other fundamental problem with the processes, but I am not advanced enough to have solved it any other way.
Originally, the delay value was only .01 sec, but I added a multiplier to the second timer loop during troubleshooting for this issue. It's probably lame, but again, it was the best ammo I have. - Form_Load calls "Stage_1." It looks as if you are trying to treat this Form as a place for synchronous processing.
I'm not sure what you mean by "synchronous processing".
In a nut shell, here is what this project does:
Stage_1 looks for information to get over the internet from several servers and stores its locations in the database.
Stage_1 generally takes about two minutes to run and during that time will add an average of 7,000 records to the Stage_1 table in the database.
Stage_2 pulls the stored data locations form the Stage_1 table, builds URLs from it, downloads the data and saves it as local files, parses the data into fields and appends it to the Stage_2 table in the database.
Stage_2 can take anywhere from 1 to 2.5 hours to run and during that time will receive and send an average of 7,000 records from the Stage_1 and Stage_2 tables.
Stage_3 runs several queries in the database to examine and normalize the data. It also checks to see if any of the data exists in the main tables already. If it does, fields are merely updated, if it does not, records are added to 6 different main tables in the database. Then it checks to see if any of the existing data has been left without updates. if it has, Stage_3 then clears the original Stage_1 and Stage_2 tables and appends portions of un-updated records to the Stage_1 table and sends the process back to start Stage_2 over.
Stage_2 repeats, with a few minor variations to save time.
when complete, Stage_3 repeats
When Stage_3 is completed the second time, the project ends. - Most of these points don't matter. I think your trouble spot is that you may be trying to run the whole program during Form_Load, or perhaps a large part of it.
I suspect you're correct here.
Essentially, the process flow does not end all the way to the end of Stage_3, once it launches from the Form_Load.
If I add "Exit Sub" after the Stage_1 line in Form_Load, will that complete the Form_Load sub or should I add a second sub in between form_load and Stage_1? - As much of the time as possible the logic in a VB6 program compiled for the Windows subsystem (and without special care this is always what you have) none of your code should be executing. Instead the program should be sitting in the (invisible) message loop awaiting a window message such as an event. Only when such events are dispatched to your handler routines should you have running code, and then only for a small amount of processing.
Well, ideally, I think I get what you're saying here, and when I run the unmodified version from the VB Editor, that is exactly (i think) what it does. Them for opens and waits for me to tell it to run with a click event on a button.
However, for the purpose of running from a scheduled task in windows, while I am out of town, I want it to just launch immediately on open, without any user inputs. Technically, it really does not matter if the form is visible or not since I won't be here, but still, I'd like to understand what is going on and why and if it can be avoided because it seems clear to me that something is technically not correct, or at least could be better. - When you have substantial "crunching" to do, you need some way to drive the process by causing events.
Well, I think I'm doing all this ok. I have several variables in the code that watch and check and count and trigger certain events, but I do not really call many outside subs. There are only two common functions between the stages. The URL2File is Public, and I have another Public for creating a zip file, but that's it.
I've considered taking the meat out of the stage_2 process and create and call public functions, but then Stage_2 is the only process that uses them and it is working as it is, so in the end I tend to leave it alone. - In the case of database access you can often use ADO objects with async method calls that raise events as each action (Execute, etc.) completes.
I think this is what I'm already doing. - Almost any time you find yourself calling the DoEvents() function it is a sign that you've broken the VB Form paradigm.
You guys blow me away every time!
Except for the help I've received in these forums, I am completely self taught in VB, and I freely admit by the standards shown in these forums, I am a complete novice. I'm sorry, but I had no idea there is a “VB Form paradigm”. I should repeat that the ONLY time I use these Timer/DoEvents loops is to slow the code down so I can see the updated values in the form's text boxes and the delay is always .01 sec. Without the delay, the code runs to completion without ever showing any of the text box updates i have stashed throughout the code. Can you elaborate on the “VB Form paradigm”?
-
Jan 9th, 2009, 07:38 PM
#9
Thread Starter
Lively Member
Re: Different Performance, EXE vs. Uncompiled Code
 Originally Posted by technorobbo
Does a_PauseTime have the text of "0.01" ? I'm asking because Timer gives the time in seconds while the API function timeGetTime or a timer control give the time in milliseconds hopefully you haven't made the wrong assumption. Since I can't see the value of PauseTime, I have to ask.
Yes, a_PauseTime has a text of .01.
-
Jan 9th, 2009, 07:40 PM
#10
Thread Starter
Lively Member
Re: Different Performance, EXE vs. Uncompiled Code
 Originally Posted by dee-u
How about trying to show it modally?
Code:
Data_Form.Show vbModal
Would I place this in the Main() or in the Form_Load() or at the beginning of Stage_1()?
-
Jan 9th, 2009, 07:47 PM
#11
Thread Starter
Lively Member
Re: Different Performance, EXE vs. Uncompiled Code
 Originally Posted by dilettante
Another option is to rewrite the program as a batch process with no Form in it at all. This could spawn a second program with Forms upon completion, to display results or errors.
Doing this almost requires linking the first program for the Console subsystem though. VB6 cannot do this unaided.
lol.
Maybe someday, but as I mentioned, the app really does what I need it to do.
I am certain it could be built better, but as much as I'd love to sit down and make it better, and in the process learn much more about it, time is a substantial challenge for me.
Besides, I think I'm going to be moving into Visual Studio 2008 soon, so i think I'll look at it then.
THANKS AGAIN FOR ALL YOU GUYS DO!!!
-
Jan 9th, 2009, 08:27 PM
#12
Re: Different Performance, EXE vs. Uncompiled Code
In VB a Form you can only write code that runs when events are raised. This code takes the form of event handling subroutines.
When the message loop code calls an event handler it expects a small amount of work to be done and then the event handler should exit. If an event handler runs for too long it starves the messge loop and eventually Windows will mark the process as "not responsive."
When you update something like a Textbox the change normally doesn't appear until the paint message this generates is processed by the message loop. This is most likely why you haven't been seeing them update on the screen.
DoEvents() is a hackish way to try to give the message loop a little breathing space but it can have severely negative consequences. This can be anything from incorrect results to failing on a stack overflow condition.
We can see where you call Stage_1, but not the following stages.
Stage_1 at least is preventing Form_Load from finishing. This is an example of synchronous processing: trying to do too much work in an event handler instead of using event-driven logic.
I'd be willing to bet almost anything that your database access is all synchronous, since very few VB programmers make async method calls to data access objects. This can work fine, as long as you aren't doing too much of it.
Calling subroutines or not has no impact on long runs of synchronous processing. The key is whether or not you exit the current event handler. If you stay in there too long you gum things up. Calling a subroutine does not make any difference.
I you want to make your Form appear you can just add a Show call (you can type this as Show or Me.Show) inside Form_Load as the first statement. This does not have the same action as Data_Form.Show from within Sub Main, which is a request to load and show the Form. The Form will not show until you call Show within the Form or until you exit Form_Load.
Don't feel bad. Lots of people write their VB code as if it were QBasic or something. Then when something doesn't work they try adding DoEvents() all over and eventually either give up or do a rewrite - or more often start moaning about how they need threading in VB6.
This isn't a VB6 issue at all, it's a Windows programming issue. Often people bail out and move to VB.Net where they can play with threading only to find this can make the problems worse.
-
Jan 10th, 2009, 07:45 PM
#13
Thread Starter
Lively Member
Re: Different Performance, EXE vs. Uncompiled Code
Thanks dilettante,
I'm going to have to chew on what you've written for me.
I think I get some of it, and I'm sure I'll have some questions, but to get the most from it, and to formulate good questions, I'll need to study it with some more time.
As for the actual issue for this thread, I have apparently resolved it as follows:
Code:
Private Sub Main()
Set adoConnection = New ADODB.Connection
adoConnection.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source= " & "C:\Database\Data_Main.mdb;"
adoConnection.Open
Data_Form.Show
End Sub
and then, in the Data_Form code:
Code:
Private Sub Form_Load()
Me.Show
Start_Harvest
Exit Sub
End Sub
Private Sub Start_Harvest()
Status_Box.Text = "Waiting for user inputs..."
a_Start = Timer ' Set start time.
Do While Timer < a_Start + a_PauseTime
DoEvents
Loop
Stage_1
Exit Sub
End Sub
Thanks for your tips.
Now I have a new issue which is addressed in this new thread
http://www.vbforums.com/showthread.p...05#post3417505
-
Jan 10th, 2009, 11:49 PM
#14
Re: [RESOLVED] Different Performance, EXE vs. Uncompiled Code
Couldn't you rewrite it like this?
Code:
Private Sub Main()
Set adoConnection = New ADODB.Connection
adoConnection.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source= " & "C:\Database\Data_Main.mdb;"
adoConnection.Open
Data_Form.Show
Data_Form.Start_Harvest
End Sub
Code:
Private Sub Form_Load()
Show
End Sub
Public Sub Start_Harvest()
Status_Box.Text = "Waiting for user inputs..."
a_Start = Timer ' Set start time.
Do While Timer < a_Start + a_PauseTime
DoEvents
Loop
Stage_1
Exit Sub
End Sub
-
Jan 11th, 2009, 08:56 AM
#15
Thread Starter
Lively Member
Re: [RESOLVED] Different Performance, EXE vs. Uncompiled Code
Thanks Dee_u, it does work!
-
Jan 12th, 2009, 01:27 AM
#16
Re: [RESOLVED] Different Performance, EXE vs. Uncompiled Code
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|