Loop i VB6 & andra problem

Elektronik- och mekanikrelaterad mjukvara/litteratur. (T.ex schema-CAD, simulering, böcker, manualer mm. OS-problem hör inte hit!)
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Inlägg av speakman »

Försök använd [ code ]-taggen så blir det mer lättläst.
F.ö. så är det i princip samma typ av kod som jag skrev, fast en annan tidkälla, vilket inte spelar någon roll i detta fall. Ännu ett alternativ hade då varit att deklarerat timeGetTime() ur WinAPI.
Problemet med denna loop är dock att om GetTickCount skulle råka slå runt precis efter man tryckt på knappen, så kommer timeouten aldrig att ske. Små odds, men man bör räkna med allt. :)
Sedan är det, som jag skrev tidigare, onödigt att ens använda sig av en deklarerad Sleep, eftersom den i sig tar 100% i VB.
Utöver det ovannämnda så blir timern ändå inte exakt, eftersom du kör Sleep 50! Det ger ju en marginal på 50ms!

Mvh
speakman
Användarvisningsbild
RRacer
Inlägg: 370
Blev medlem: 29 januari 2005, 19:40:17
Ort: Lerum

Inlägg av RRacer »

speakman skrev:Försök använd [ code ]-taggen så blir det mer lättläst.
F.ö. så är det i princip samma typ av kod som jag skrev, fast en annan tidkälla, vilket inte spelar någon roll i detta fall. Ännu ett alternativ hade då varit att deklarerat timeGetTime() ur WinAPI.
Problemet med denna loop är dock att om GetTickCount skulle råka slå runt precis efter man tryckt på knappen, så kommer timeouten aldrig att ske. Små odds, men man bör räkna med allt. :)
Sedan är det, som jag skrev tidigare, onödigt att ens använda sig av en deklarerad Sleep, eftersom den i sig tar 100% i VB.
Utöver det ovannämnda så blir timern ändå inte exakt, eftersom du kör Sleep 50! Det ger ju en marginal på 50ms!

Mvh
speakman
Den inbyggda timern har en upplösning på 1/18.2 sekunder vilket gör att den blir väldigt oprecis, i synnerhet med längre tidsintervall.

Vet inte vad du menar med "slå runt", men som du analyserar koden igen så ska du se att några missar inte kommer att inträffa så länge koden hinner exekveras innan nästa tidsintervall inträffar.

Vad beträffar Sleep() så ber jag dig köra koden med resp. utan den och jämföra CPU-belastningen så kommer du att förstå.

Sleep 50 ryms ledigt i OP:s krav på 100 ms slingor. Vad är konstigt med det? Slingan blir EXAKT!
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Inlägg av speakman »

För det första, var vänlig läs de få reglerna på forumet.

För det andra; GetTickCount är precis som alla andra tillgängliga systemtimrar en 32-bitars räknare, och slår om då talet når > 2^32 = 4294967296ms, alltså ca 49,7 dagar (därav min notis om små odds, men man bör räkna med möjligheten!).
Om nu GetTickCount är 10ms från 2^32 och du vill ha en timeout på 500ms så kommer antingen VB å stanna om du använder 32-bitars variabel, eller så kommer den aldrig att lösa ut om du använder en bredare variabel.

Sedan grundas timeGetTime/GetTickCount/Timer på samma källa, så jag förstår inte vad som skulle skilja där.
Ska man ha RIKTIGT bra precision så bör man använda QueryPerformanceFrequency/QueryPerformanceCounter.

Sedan var det länge sedan jag försökte använda Sleep för att minska belastningen, men då fungerade det inte. Antar att du har beläggning för att det fungerar bättre nu.

Din "Sleep 50" gör också att koden efter kommer att exekveras minst 50ms efter, vilket ger ett eftersläp om tiden gick ut precis efter den entrat Sleep 50.

Men jag tror t.o.m. Timer-objektet var precision nog för Cenorpas ändamål. :)

Mvh
speakman
v-g
EF Sponsor
Inlägg: 7875
Blev medlem: 25 november 2005, 23:47:53
Ort: Kramforce

Inlägg av v-g »

RRacer & Speakman: Kan det bli mer exakt än om man tar systemets starttid och sedan subtraherar den från sluttiden? Du har ju plockat tiden från systemet och inte på något sätt räknat på den. Sålänge systemet och hårdvaran i maskinen inte räknar fel så fungerar det.

Hoppas ni inte blandar samman timer med timer. Den man skapar på "panelen" är EJ exakt över längre tidsperioder det har jag testat, den är inte avsedd för detta heller. Timer ur "systemet" _ÄR_ exakt eftersom detta är en beräkning av antalet sekunder sen midnatt. Enda gången den är lite dum är när man går över dyngsgränsen.

Mitt senaste exempel är 100% exakt förrutom fördröjningen från ev knapptryck --> det händer något.

VB i det stora är antagligen inte avsett för superexakta tidskritiska program. Men för vanliga dödliga tycker jag det duger gott och väl.
Användarvisningsbild
RRacer
Inlägg: 370
Blev medlem: 29 januari 2005, 19:40:17
Ort: Lerum

Inlägg av RRacer »

Speakman: Ok, alla räknare slår runt till slut. Jag har inte påstått att mitt exempel var färdigt eller felfritt.

Gör några tester med GetTickCount - du får 1 ms upplösning.

Sleep är jättebra om man använder den med huvudet. Jag har kört mitt exempel (kompilerat) i drygt 30 minuter nu, och ännu inte ackumulerat upp en enda sekund i CPU-tid i taskmanager. Jag provkörde ditt exempel, och det tog 100% CPU och låste VB!

Sleep 50 kommer att orsaka en eftersläpning i exekveringen OM du väljer att lägga din aktiva kod EFTER sleep-satsen. Men det väljer man ju själv.

EDIT: WHOAA! Jag upptäckte att Sleepsatsen körs VARJE varv i slingan! Det är ju självfallet inte meningen. Poäng till Speakman.
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43178
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Inlägg av sodjan »

Jag tycker att det råder förvirring kring "precision" resp "upplösning"...
Kanske bäst att reda ut vilket som avses.

En tidsmätning kan ju ha bra "precision" men dålig "upplösning".
Och även tvärtom så klart.
Användarvisningsbild
RRacer
Inlägg: 370
Blev medlem: 29 januari 2005, 19:40:17
Ort: Lerum

Inlägg av RRacer »

v-g skrev:...hoppas ni inte blandar samman timer med timer. Den man skapar på "panelen" ...
VB i det stora är antagligen inte avsett för superexakta tidskritiska program. Men för vanliga dödliga tycker jag det duger gott och väl.
Det kan nog vara lite förvirrat... timers har använts om både VB:s intrinsic timer samt systemtimers lite huller om buller i tråden.

Visst är det så att ska man ha extrem upplösning/precision (take your pick, Janne :wink: ) så är inte VB förstahandsvalet. Hög nogrannhet kostar CPU som det ser ut nu. Det är möjligt att det har förändrats i VB.NET, har inte analyserat det närmare (övergången till .NET är tung, VB6 känns "hemma").
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Inlägg av speakman »

Testade denna lilla snurra:

Kod: Markera allt

Private Sub Form_Load()
    Do
        Debug.Print GetTickCount
        DoEvents
    Loop
End Sub
Resultatet blev ca 40st "1372122500", sedan direkt ca 40st "1372122515". Vad säger det? Jo att systemets upplösning (som egentligen är specat till 10ms) endast är dryga 15ms!
Precis samma sak get timeGetTime också, och även Timer (i princip).
Ska man ha högre precision så måste man använda sig av QueryPerformanceFrequency/QueryPerformanceCounter.

Sedan kan man givetvis subtrahera starttid från sluttid, men då har man fortfarande problemet med "overflow" i 32-bitars timern. :)
Men som sagt, jag vet inte vad syftet var, det kanske inte gör något om en tidtagning falerar så det går att göra om?
Då jag har behövt hög precision hade det dessvärre inte fungerat, varav man måste tänka ut alternativ lösning. Och då offra 100% CPU under en stund.
Dock ska definitivt _inget_ hänga sig om man kör DoEvents varje varv! Det är just det som är poängen med funktionen.

Däremot funkar ju Sleep betydligt bättre nu än på den tiden jag höll på å prova, var förresten på en Win2k-burk.

Men slutligen: Är man ute efter hög precision i VB så får man offra en stunds fullständig CPU-kraft. Är vi överens om det? :)

Mvh
speakman
Användarvisningsbild
Cenorpa
Inlägg: 737
Blev medlem: 11 juli 2005, 20:58:03
Ort: Stockholm | Borlänge
Kontakt:

Inlägg av Cenorpa »

Min applikation är inte lika krävande som jag trodde från början så jag kör med det första förslaget med timern.
Tack för all hjälp och alla förslag, fast jag är ju nybörjare på VB så jag ska inte göra det för avancerat för mig.
Användarvisningsbild
RRacer
Inlägg: 370
Blev medlem: 29 januari 2005, 19:40:17
Ort: Lerum

Inlägg av RRacer »

speakman skrev:...att systemets upplösning (som egentligen är specat till 10ms) endast är dryga 15ms!
Precis samma sak get timeGetTime också, och även Timer (i princip).
Ska man ha högre precision så måste man använda sig av QueryPerformanceFrequency/QueryPerformanceCounter.
...
Ja, om man inte gör så här:

Kod: Markera allt

Public Declare Function timeGetTime Lib "winmm.dll" () As Integer
Public Declare Function timeBeginPeriod Lib "winmm.dll" (ByVal uPeriod As Long) As Long
Public Declare Function timeEndPeriod Lib "winmm.dll" (ByVal uPeriod As Long) As Long

Private Sub Form_Load()
    Dim i As Long
    timeBeginPeriod 1
    For i = 1 To 500 ' Borde räcka...
        Debug.Print timeGetTime()
    Next i
    timeEndPeriod 1
    Debug.Print "Millisecond resolution!"
End Sub
Nu med CODE taggar!

Jag visste att det gick, men mitt minne svek mig. Här är iallafall ett sätt att få 1 ms upplösning. Till Janne: siffrorna hoppar till ibland pga egenheterna i Windows, så noggrannheten får vi diskutera.

Exempel på utdata:
4128
4129
4129
4129
4129
4130
4130
4130
4130
4131
4131
4131
4132
4132
4132
4133
4133
4133
4133
4134
4134
4134

Kanske dags för en lur nu...
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Inlägg av speakman »

Se där! Får buga mig för den! :)
Fungerar kalas i Win2k också för den delen.
- "ms should be enough for everyone", kanske farligt uttryck! :D

Ska man ha högre precision än så där, så är det nog hårdvaruklockor som gäller, som kan nollas mjukvarumässigt! :)

Mvh
speakman
Användarvisningsbild
Cenorpa
Inlägg: 737
Blev medlem: 11 juli 2005, 20:58:03
Ort: Stockholm | Borlänge
Kontakt:

Inlägg av Cenorpa »

Ett litet nytt problem.

Har kommet till ett ställe i programet då det har blivit nödvändigt att skriva en miljon if satser vilket är lite tråkigt så jag undrar om man kan göra på något annat sätt.

Såhär ser koden ut:

If fx = x Then
fxb(0).Visible = True
fxb(0).Left = effectvar
IntFx0 = effectvar
End If

If fx = x Then
fxb(1).Visible = True
fxb(1).Left = effectvar
IntFx1 = effectvar
End If

o.s.v

Kan man på något sätt byta ut siffran inom parantes i namnet med en variabel och lägga det i en loop som räknar upp och kollar igenom allt?

Det jag vill göra är ungefär såhär:

If fx = x Then
fxb(y).Visible = True
fxb(y).Left = effectvar
IntFxy = effectvar
End If

Så hur löser man det, en miljon IF satser eller någon enkel loop?
Användarvisningsbild
RRacer
Inlägg: 370
Blev medlem: 29 januari 2005, 19:40:17
Ort: Lerum

Inlägg av RRacer »

Kod: Markera allt


for y=0 to 999999
  If fx = x Then 
    fxb(y).Visible = True 
    fxb(y).Left = effectvar 
    IntFx(y) = effectvar 
  End If 
next y
Du måste indexera IntFx.

HTH
Användarvisningsbild
Cenorpa
Inlägg: 737
Blev medlem: 11 juli 2005, 20:58:03
Ort: Stockholm | Borlänge
Kontakt:

Inlägg av Cenorpa »

En liten till fråga då, hur indexerar jag IntFx?
IntFx är variablar, IntFx0 till IntFx30
Användarvisningsbild
RRacer
Inlägg: 370
Blev medlem: 29 januari 2005, 19:40:17
Ort: Lerum

Inlägg av RRacer »

Dim IntFx(30)

Du måste ha lika många element i IntFx() som du har i fxb() för att slingan ovan ska funka.
Skriv svar