[Java] File openen binnen bepaalde tijd

Pagina: 1
Acties:

  • sig69
  • Registratie: Mei 2002
  • Laatst online: 20:41
Ik hoop dat de Java kenners al wakker zijn :)

Ik heb een applicatie die een aantal bestanden inleest van diverse (netwerk) locaties. Sinds vanochtend ligt een gedeelte van het netwerk plat, waardoor een aantal bestanden dus niet bereikbaar zijn. Hierdoor duurt het laden van bestanden erg lang, omdat hij voor elk bestand die niet beschikbare netwerklocatie probeert te openen, waar hij een kleine minuut op hangt. Op zich niet erg, maar bij een bestand of 10 wordt het vervelend. Nu wil ik dus een bepaalde check doen of een locatie wel beschikbaar is. De bestanden worden per locatie ingelezen, dus ik wil eerst een soort check of die locatie beschikbaar is, en zo niet alle bestanden op die locatie overslaan. Zo gezegd, zo gedaan zou je denken..

Ik had eerst dit:
Java:
1
2
3
File f = new File("\\\\netwerkcomputer\\");
if(!f.canRead())
    return;

Dit werkt prima voor bestanden die wel of niet bestaan, of als de netwerklocatie wel bestaat. Maar als de netwerklocatie niet bestaat, blijft hij wederom een hele tijd hangen waar ik me dus aan stoor. Wat ik nu dus eigenlijk wil, is dat hij maximaal een bepaalde tijd (3seconden ofzo) probeert te kijken of hij een locatie kan openen, en daarna stopt. Ik weet alleen niet zo goed hoe ik dit aan moet pakken.

Ideeen die ik heb:
  • Ik moet iets met threads doen, omdat f.canRead() anders de hele app locked
  • Ik heb een timer nodig.
Ik heb al een beetje lopen spelen, maar ik heb nog niet zoveel ervaring met threads en kan wel een duwtje in de goede richting gebruiken...

[ Voor 3% gewijzigd door sig69 op 10-11-2005 10:15 ]

Roomba E5 te koop


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Het nadeel aan een thread gebruiken is dat het lastiger is om op de orginele flow van je systeem terug te komen. Wat je zou kunnen doen is het volgende. Je opent 1 bestand. Duurt dit openen langer dan bv 10 seconden, dan ga je de rest niet meer proberen.

Hoe moet je systeem trouwens omgaan met files die niet geopend kunnen worden? Gaat dit geen problemen opleveren?

  • bigbeng
  • Registratie: Augustus 2000
  • Laatst online: 26-11-2021
Gezien je voorbeeldcode werk je met een windows netwerk. Kun je niet proberen de betreffende machine 4x oid te pingen (voorbeeld ping app) en als dat tenminste 1x lukt pas de file proberen te openen?

[ Voor 20% gewijzigd door bigbeng op 10-11-2005 10:21 ]


  • sig69
  • Registratie: Mei 2002
  • Laatst online: 20:41
Alarmnummer schreef op donderdag 10 november 2005 @ 10:18:
Het nadeel aan een thread gebruiken is dat het lastiger is om op de orginele flow van je systeem terug te komen. Wat je zou kunnen doen is het volgende. Je opent 1 bestand. Duurt dit openen langer dan bv 10 seconden, dan ga je de rest niet meer proberen.
Dat is ongeveer wat ik nu ook heb, alleen duurt het openen van dat ene bestand ook nog erg lang. Als het langer dan 10 seconden duurt weet ik in principe genoeg en mag hij van mij stoppen met proberen.
Hoe moet je systeem trouwens omgaan met files die niet geopend kunnen worden? Gaat dit geen problemen opleveren?
Dat is geen probleem. Elk bestand representeert een eigen set data die op zichzelf staat, dus als er bestanden ontbreken werkt de applicatie gewoon verder.
bigbeng schreef op donderdag 10 november 2005 @ 10:19:
Gezien je voorbeeldcode werk je met een windows netwerk. Kun je niet proberen de betreffende machine 4x oid te pingen (voorbeeld ping app) en als dat tenminste 1x lukt pas de file proberen te openen?

Dit is wel een aardig idee, alleen moet ik dan onderscheid gaan maken tussen netwerklocaties en lokale bestanden. En, erger, soms worden er ook netwerkschijven gebruikt waardoor dus niet meer te achterhalen is dat het een netwerklocatie betreft.

Roomba E5 te koop


  • wasigh
  • Registratie: Januari 2001
  • Niet online

wasigh

wasigh.blogspot.com

Ik zou het toch proberen asynchroon in te laden. En een TimeOut event throwen wanneer het inladen te lang duurt. Een beetje zoals de MediaTracker ook werkt.

Je zult dan idd met Threads moeten werken. Wat niet heel lastig is (zolang je niet met al teveel Threads werkt) Een thread is in de basis niets anders dan een Class die de interface runnable implementeerd. Zorg dat je de bestanden door kunt geven, en zorg dat hij Events naar een listener kan sturen.

Als het inladen van een File langer duurt dan een aantal seconden schiet je de thread af en report je hem als failure..

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

sig69 schreef op donderdag 10 november 2005 @ 10:38:
[...]

Dat is ongeveer wat ik nu ook heb, alleen duurt het openen van dat ene bestand ook nog erg lang.
Dan is misschien een aparte thread wel handig. Algemene waarschuwing: gebruik bijna nooit een new Thread() oid. Je kunt threads veel beter laten beheren door een component waarmee je controle houd. Stel dat een gebruiker als een zotte op knoppen loopt te rammen, dan krijg je voor iedere fileload een thread en dat wil je dus niet. Daarom maak ik bijna altijd gebruik van ExecutorServers.

Voorbeeld van een runnable.
code:
1
2
3
4
5
6
7
8
class FileLoadTask implements Runnable{
     private File _file; //geef mee via constructor.
  
    void run(){
             ...laad de file
            ...geef door dat de file geladen is.
    }
}


En die geef ik dan aan een executorservice (hoef je maar 1 van aan te maken en kan je delen tussen alle onderdelen die iets met threads wilt doen.

vb van aanmaak:

ExecutorService executor = Executors.newFixedThreadPool(5);

En dan kan je je taak gewoon in die executor kieperen.

executor.execute(new FileLoadTask(fileDieJeWiltLaden));

Op deze manier hou je heel goed onder controle hoeveel threads er bv draaien. In dit geval kunnen nooit meer dan 5 threads tegelijk draaien. Ik lijm dit soort dingen meestal op in Spring en initialiseer en sluit de executors op het moment dat de applicatie start/afsluit. Verder kun je ook controle houden op het aantal taken dat de executor maximaal mag opslaan voordat hij ze gaat verwerken. Ik werk zelf eigelijk nooit met de Executors class, maar ik maak altijd ThreadPoolExecutors aan via de constructor omdat ik alle dingen tot in de kleinste puntjes wil controleren (oa thread prioriteiten, threadnamen/threadgroeps/command queues etc).
Als het langer dan 10 seconden duurt weet ik in principe genoeg en mag hij van mij stoppen met proberen.
Dat zou je in de taak kunnen zetten, vb:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
class FileLoadTask implements Runnable{
     private File _file; //geef mee via constructor.
  
    void run(){
            long startTime =  System.currentTimeInMilis();
            ...laad de file
            long endTime = System.currentTimeInMilis();

            if(endTime-startTime<maximaleWachttijd){
                 ...geef door dat de file geladen is.
            }
    }
}


Waarschuwing:
pas trouwens wel heel goed op met het doorgeven dat die file geladen is. Als je werkt met Swing kun je het beste een 'ik ben klaar' runnable op de EventDispatchingThread laten uitvoeren. Op die manier heb je in Swing in ieder geval totaal geen last meer concurrency problematiek.

vb:

code:
1
2
3
4
5
class IkBenklaarRunnable implements Runnable{
   void run(){
        ... geef door dat de file geladen is.
   }
}


En deze afvuren met:
SwingUtilties.invokeLater(new IkBenKlaarRunnable());

[ Voor 12% gewijzigd door Alarmnummer op 10-11-2005 10:55 ]


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

wasigh schreef op donderdag 10 november 2005 @ 10:45:
Als het inladen van een File langer duurt dan een aantal seconden schiet je de thread af en report je hem als failure..
Afschieten van threads is erg link omdat het dan kan gebeuren dat interne structuren niet goed achterblijven en het systeem corrupt raakt. Je kunt de interrupt flag in de thread aanzetten en hopen dat de er bij het inlezen rekening mee gehouden gaat worden, maar die kans is meestal heel erg klein.

Ik schiet zelf liever geen threads af omdat dit gewoon te veel risico`s met zich mee brengt. Verder schiet ik sowieso geen threads af omdat mijn threads altijd worden beheerd door andere componenten en die threads wil je echt niet afschieten.

[ Voor 11% gewijzigd door Alarmnummer op 10-11-2005 11:03 ]


  • wasigh
  • Registratie: Januari 2001
  • Niet online

wasigh

wasigh.blogspot.com

Alarmnummer schreef op donderdag 10 november 2005 @ 10:50:
[...]


code:
1
2
3
4
5
6
7
8
9
10
11
12
13
class FileLoadTask implements Runnable{
     private File _file; //geef mee via constructor.
  
    void run(){
            long startTime =  System.currentTimeInMilis();
            ...laad de file
            long endTime = System.currentTimeInMilis();

            if(endTime-startTime<maximaleWachttijd){
                 ...geef door dat de file geladen is.
            }
    }
}
Gaat dit werken? In mijn beleving is het laden van een file een synchrone actie. Dus zal hij hier altijd de hele file laden. en achteraf kijken of hij er te lang over gedaan heeft. Ik zat meer te denken in de trand van: (preciese code van starten van Threads even buiten beschouwing gelaten..)

Java:
1
2
3
4
5
6
7
Thread fileThread = new Thread(runnableClass); 
Thread.Wait(4000);
if (!fileThread.completed)
{
   fileThread.failed();
   return "helaas...";
}


of misschien geen thread.sleep maar een while loop;
Java:
1
2
3
4
5
6
7
8
9
long start = CurrentTimeMillis();
long end = CurrentTImeMillis()

while(!fileThread.finishedLoading & end-start < 4000)
{
   end = CurrentTimeMillis
}

// hier is oftewel het bestand geladen, oftewel de timeout is verstreken..


(overigens is het geen werkende code, het geeft een idee weer ;) )

  • wasigh
  • Registratie: Januari 2001
  • Niet online

wasigh

wasigh.blogspot.com

Alarmnummer schreef op donderdag 10 november 2005 @ 10:58:
[...]

Afschieten van threads is erg link omdat het dan kan gebeuren dat interne structuren niet goed achterblijven en het systeem corrupt raakt. Je kunt de interrupt flag in de thread aanzetten en hopen dat de er bij het inlezen rekening mee gehouden gaat worden, maar die kans is meestal heel erg klein.

Ik schiet zelf liever geen threads af omdat dit gewoon te veel risico`s met zich mee brengt. Verder schiet ik sowieso geen threads af omdat mijn threads altijd worden beheerd door andere componenten en die threads wil je echt niet afschieten.
Ik bedoelde ook niet de stop(). Ik bedoelde een constructie waarmee je aangeeft dat een thread mag stoppen. En dan in de run() de thread ook echt laat stoppen..

Ik had er wat duidelijker in moeten zijn idd!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

wasigh schreef op donderdag 10 november 2005 @ 11:03:
[...]


Gaat dit werken? In mijn beleving is het laden van een file een synchrone actie. Dus zal hij hier altijd de hele file laden. en achteraf kijken of hij er te lang over gedaan heeft.
Yep. Maar je kunt er wel voor kiezen om files die er heel lang over hebben gedaan, niet meer aan de gebruiker te laten zien (dus het resultaat gewoon negeren). Ik weet niet of dit een eis is.
(overigens is het geen werkende code, het geeft een idee weer ;) )
Ik snap wat je bedoelt. Maar dat kan ook uitstekend met de executorservice:

Future f = executorService.submit(new FileLoadRunnable());
f.get(5,TimeUnit.SECONDS);

Als je nu een Timeoutexception voor de kiezen krijgt dan weet je dat het niet binnen de voorgestelde tijd is gelukt. het probleem aan deze oplossing is dat je de event dispatching thread wel aan het blokkeren bent.

[ Voor 4% gewijzigd door Alarmnummer op 10-11-2005 11:12 ]


  • wasigh
  • Registratie: Januari 2001
  • Niet online

wasigh

wasigh.blogspot.com

Alarmnummer schreef op donderdag 10 november 2005 @ 11:10:


Als je nu een Timeoutexception voor de kiezen krijgt dan weet je dat het niet binnen de voorgestelde tijd is gelukt. het probleem aan deze oplossing is dat je de event dispatching thread wel aan het blokkeren bent.
Yep, daar heb je een punt. Dus zou je die code eigenlijk ook weer in een Thread willen zetten.
Oftwel een Thread die door middel van andere Threads de bestanden inleest.

Overigens vind ik jou oplossing mooier ;) (al zal die onderwater ongeveer hetzelfde doen?)

  • sig69
  • Registratie: Mei 2002
  • Laatst online: 20:41
Ok ik heb wat dingen uit het topic in combinatie met wat eigen hersenspinsels gebruikt, en ik ben tot het volgende gekomen:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class TimedFile implements Runnable
{
    private static final long MAX_TIME = 4000;
    private boolean bRunning;
    private boolean bExists;
    private long start;
    private long end;
    private File f;

    public TimedFile(String path)
    {
        super();
        f = new File(path);
    }

    public boolean exists()
    {
        run();
        while(bRunning && (end - start) < MAX_TIME)
        {
            end = System.currentTimeMillis();

            try
            {
                Thread.sleep(10);
            }
            catch (InterruptedException e)
            {
            }
        }
        return bExists;
    }

    public void run()
    {
        bRunning = true;
        start = System.currentTimeMillis();
        Timer t = new Timer();
        t.schedule(new TimerTask()
                {
                    public void run()
                    {
                        bExists = f.exists();
                        bRunning = false;

                    }           
                }, 
                0);
    }
}

Ik heb er zelf een gevoel bij van "Tsja, het werkt"... Wat vinden jullie?

Roomba E5 te koop


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Waarom start je nog een keer een Timer? En hoe start je deze runnable?

  • sig69
  • Registratie: Mei 2002
  • Laatst online: 20:41
De timer start ik omdat dat ook een nieuwe thread start, anders locked de f.exists() deze thread en kan ik dus niet bepalen of hij al langer dan een bepaalde tijd bezig is.
(Geinspireerd door wasigh):
Yep, daar heb je een punt. Dus zou je die code eigenlijk ook weer in een Thread willen zetten.
Oftwel een Thread die door middel van andere Threads de bestanden inleest.
De run zit in de exists methode, weet niet zeker of dat netjes is, een thread die zichzelf start?

[ Voor 32% gewijzigd door sig69 op 10-11-2005 11:43 ]

Roomba E5 te koop


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

sig69 schreef op donderdag 10 november 2005 @ 11:42:
De timer start ik omdat dat ook een nieuwe thread start, anders locked de f.exists() deze thread en kan ik dus niet bepalen of hij al langer dan een bepaalde tijd bezig is.
Het blokkeren is geen probleem omdat de jouw runnable al op zijn eigen thread draait (als je hem opstart via zo`n ExecutorService). Dat was het hele idee achter die runnable.

Dus gewoon dit doen:
ExecutorService executor = ... haal de executor op
executor.execute(new TimedFile(deFile));

En hernoem die TimedFile naar FileLoadTask oid. Het is namelijk geen File, maar een taak die een file load.

[ Voor 27% gewijzigd door Alarmnummer op 10-11-2005 11:50 ]


  • sig69
  • Registratie: Mei 2002
  • Laatst online: 20:41
Alarmnummer schreef op donderdag 10 november 2005 @ 11:44:
[...]

Het blokkeren is geen probleem omdat de jouw runnable al op zijn eigen thread draait (als je hem opstart via zo`n ExecutorService). Dat was het hele idee achter die runnable.

Dus gewoon dit doen:
ExecutorService executor = ... haal de executor op
executor.execute(new TimedFile(deFile));
Hier ga ik even naar kijken...
Edit: dit gaat helaas niet op, we werken hier nog met 1.4.2
En hernoem die TimedFile naar FileLoadTask oid. Het is namelijk geen File, maar een taak die een file load.
Is waar, doe ik.

[ Voor 5% gewijzigd door sig69 op 10-11-2005 12:08 ]

Roomba E5 te koop


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Ik gebruik vrij veel threading componenten serverside en mijn eisen zijn ook vrij hoog. Dus problemen die ik hier schets (zoals ongecontroleer thread aanmaak) zullen bij een normale applicatie minder belangrijk zijn. Een ook al crasht een normale applicatie, de gevolgen hiervan zijn veel minder ernstig dan een server crash.

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

sig69 schreef op donderdag 10 november 2005 @ 12:03:
[...]

Hier ga ik even naar kijken...
Edit: dit gaat helaas niet op, we werken hier nog met 1.4.2
http://www.harness2.org/util/backport-util-concurrent/

Een backport voor java 1.4

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

En waar ben je nu op uitgekomen?

  • KopjeThee
  • Registratie: Maart 2005
  • Niet online
Toch nog even een kleine opmerking waar je waarschijnlijk al aan hebt gedacht. Je moet je wel realiseren dat je geen onderscheid kunt maken tussen een onbereikbare computer en een (hele) trage. Als je de time-outs kleiner maakt, wordt de kans groter dat je ten onrechte een computer als onbereikbaar aanmerkt, terwijl hij gewoon een beetje traag was.

  • sig69
  • Registratie: Mei 2002
  • Laatst online: 20:41
Ik laat het nog even bij wat ik hiervoor al had gepost, d'r kwam even wat tussen dus ik moet me nog een keer gaan verdiepen in die executorService.
kopjethee schreef op vrijdag 11 november 2005 @ 07:47:
Toch nog even een kleine opmerking waar je waarschijnlijk al aan hebt gedacht. Je moet je wel realiseren dat je geen onderscheid kunt maken tussen een onbereikbare computer en een (hele) trage. Als je de time-outs kleiner maakt, wordt de kans groter dat je ten onrechte een computer als onbereikbaar aanmerkt, terwijl hij gewoon een beetje traag was.
Langzame computers hebben we hier niet :)
Maar ik had er ook al aan gedacht ja, de maximale tijd is geen constante meer maar configureerbaar. Overigens doet de check of de file al dan niet bestaat er doorgaans tussen de 0 en 20 ms over, dus zodra je aan de 5 a 10 seconden zit is er iets goed fout.

Roomba E5 te koop


  • misfire
  • Registratie: Maart 2001
  • Laatst online: 12-10-2024
Als je toch gebruik kunt maken van Java 5 dan zou je ook kunnen proberen of het volgende werkt:

Java:
1
2
3
4
URL url = new URL("file:///c:/foo.bar");
URLConnection connection = url.openConnection();
connection.setConnectTimeout(2); // 2 millisecs
connection.connect();


Ik heb helaas geen slome resource om te testen of dit werkt. :)

  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

sig69 schreef op donderdag 10 november 2005 @ 11:36:
Ik heb er zelf een gevoel bij van "Tsja, het werkt"... Wat vinden jullie?
- Je hebt nergens een timedFile instantie (intern in de run() van timedFile) waarvan je de exists() aanroept, dus die wordt nooit aangeroepen.
- Daarnaast moet je nooit zelf run() aanroepen, want dan start je geen nieuwe thread. Je moet start() aanroepen en die regelt de aanroep van run(). Run() zelf aanroepen is als een gewone methode aanroepen
- Waarom niet gewoon sleep(MAX_TIME)? Ik zie geen reden het ding elke 10 ms iets te laten doen.

[ Voor 35% gewijzigd door Confusion op 12-11-2005 12:09 ]

Wie trösten wir uns, die Mörder aller Mörder?


  • dingstje
  • Registratie: Augustus 2002
  • Laatst online: 02-01-2024
Confusion schreef op zaterdag 12 november 2005 @ 12:07:
- Waarom niet gewoon sleep(MAX_TIME)? Ik zie geen reden het ding elke 10 ms iets te laten doen.
Als de file ingelezen is met succes (wat waarschijnlijk het meeste voorkomt) duurt het maar 10 of 20 ms. Als je sleep(MAX_TIME) zou gebruiken met MAX_TIME = 4000 en dat voor 10 bestanden moet de gebruiker sowieso 40 seconden wachten ongeacht fail of success (of indien je bij één check alles laat vallen 4 seconden). Dat lijkt me een redelijk lange periode dat je je gebruiker moet laten wachten.

[ Voor 3% gewijzigd door dingstje op 12-11-2005 12:46 ]

If you can't beat them, try harder


  • 4of9
  • Registratie: Maart 2000
  • Laatst online: 15-04 15:52
ik heb ongeveer hetzelfde probleem een keer gehad bij het deleten van files (deze kunnen ingebruik zijn en daardoor de applicatie laten hangen.

het is in C# maar misschien heb je er iets aan.

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
        public bool DeleteTempFiles()
        {
            int no_retries = 0;
            int i = 0;
            string path;
    
            DirectoryInfo di = new DirectoryInfo(_directory);
            FileInfo[] fi = di.GetFiles();
            
            while(no_retries < _retrycount && i < fi.Length)
            {
                path = fi[i].Directory + @"\" + fi[i].Name;

                if(!this.DeleteFile(path))
                {
                    no_retries++;
                    Thread.Sleep(_retryinterval);
                }
                else
                {
                    i++;
                }
            }
            return (i == fi.Length);
        }

    

    private bool DeleteFile(string path)
    {
        bool retval = false;
        try
        {
            File.Delete(path);
            retval = true;
        }
        catch(Exception)
        {
            retval = false;
        }
        return retval;
    }

Aspirant Got Pappa Lid | De toekomst is niet meer wat het geweest is...


  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

dingstje schreef op zaterdag 12 november 2005 @ 12:46:
Als de file ingelezen is met succes (wat waarschijnlijk het meeste voorkomt) duurt het maar 10 of 20 ms. Als je sleep(MAX_TIME) zou gebruiken met MAX_TIME = 4000 en dat voor 10 bestanden moet de gebruiker sowieso 40 seconden wachten ongeacht fail of success (of indien je bij één check alles laat vallen 4 seconden). Dat lijkt me een redelijk lange periode dat je je gebruiker moet laten wachten.
Je hebt toch geen 4 seconden nodig om te weten of er op het netwerk iets beschikbaar is? Een tiende seconde is al een eeuwigheid in computertijd.

Wie trösten wir uns, die Mörder aller Mörder?

Pagina: 1