2010-11-26 17 views
1

Ich habe zwei Methoden, die ich ausführen muss, können wir sie nennen metA und metB.iphone - wie mache ich einen Thread läuft schneller

Als ich mit der Programmierung dieser App begann, habe ich beide Methoden ohne Threads aufgerufen, aber die App begann zu frieren, also entschied ich mich, mit Threads zu gehen.

metA und metB werden durch Berührungsereignisse aufgerufen, so dass sie jederzeit in beliebiger Reihenfolge auftreten können. Sie sind nicht voneinander abhängig.

Mein Problem ist die Zeit, die es dauert, bis beide Threads gestartet werden. Zwischen dem Zeitpunkt, zu dem der Thread erstellt wird, und dem Zeitpunkt, zu dem der Thread gestartet wird, gibt es eine Verzögerung zwischen dem Erstellen des Threads und dem Erstellen des Threads.

Ich nehme an, diese Zeit hängt mit der Zeit zusammen, die iOS benötigt, um den Thread selbst zu erstellen. Wie kann ich das beschleunigen? Wenn ich beide Threads vorbereite, wie kann ich sie dazu bringen, einfach ihre Sachen zu machen, wenn sie gebraucht werden, und niemals enden? Ich meine, eine Art schlafender Faden, der immer lebendig ist und funktioniert, wenn man danach fragt und schläft?

danke.

+0

Wie viel von einem Lag sehen Sie? – hotpaw2

+0

Etwa 0,18 Sekunden. Eine reguläre Methode, die direkt aufgerufen wird, gibt mir 0,07. Ich messe die Zeit, die benötigt wird, um die erste Zeile der Methode auszuführen. Weniger als die Hälfte der Zeit. – SpaceDog

Antwort

3

Wenn Sie die teure Startzeit beim Erstellen neuer Threads vermeiden möchten, erstellen Sie beide Threads beim Start wie vorgeschlagen. Um sie nur bei Bedarf ausführen zu lassen, können Sie sie auf eine Zustandsvariable warten lassen. Da Sie die Klasse NSThread für das Threading verwenden, würde ich die Klasse NSCondition für Bedingungsvariablen empfehlen (eine Alternative wäre die Verwendung des POSIX-Threading (Pthread) condition variables, pthread_cond_t).

Eine Sache, auf die Sie achten müssen, ist, wenn Sie ein weiteres Berührungsereignis erhalten, während der Thread noch läuft. In diesem Fall würde ich empfehlen, eine Warteschlange zu verwenden, um Arbeitsaufgaben zu verfolgen, und dann kann der Touch-Ereignishandler das Arbeitselement einfach der Warteschlange hinzufügen, und der Arbeitsthread kann sie verarbeiten, solange die Warteschlange nicht leer ist.

Hier ist ein Weg, dies zu tun:

typedef struct WorkItem 
{ 
    // information about the work item 
    ... 
    struct WorkItem *next; // linked list of work items 
} WorkItem; 

WorkItem *workQueue = NULL; // head of linked list of work items 
WorkItem *workQueueTail = NULL; // tail of linked list of work items 
NSCondition *workCondition = NULL; // condition variable for the queue 

... 

-(id) init 
{ 
    if((self = [super init])) 
    { 
     // Make sure this gets initialized before the worker thread starts 
     // running 
     workCondition = [[NSCondition alloc] init]; 

     // Start the worker thread 
     [NSThread detachNewThreadSelector:@selector(threadProc:) 
             toTarget:self withObject:nil]; 
    } 

    return self; 
} 

// Suppose this function gets called whenever we receive an appropriate touch 
// event 
-(void) onTouch 
{ 
    // Construct a new work item. Note that this must be allocated on the 
    // heap (*not* the stack) so that it doesn't get destroyed before the 
    // worker thread has a chance to work on it. 
    WorkItem *workItem = (WorkItem *)malloc(sizeof(WorkItem)); 

    // fill out the relevant info about the work that needs to get done here 
    ... 
    workItem->next = NULL; 

    // Lock the mutex & add the work item to the tail of the queue (we 
    // maintain that the following invariant is always true: 
    // (workQueueTail == NULL || workQueueTail->next == NULL) 
    [workCondition lock]; 
    if(workQueueTail != NULL) 
     workQueueTail->next = workItem; 
    else 
     workQueue = workItem; 
    workQueueTail = workItem; 
    [workCondition unlock]; 

    // Finally, signal the condition variable to wake up the worker thread 
    [workCondition signal]; 
} 

-(void) threadProc:(id)arg 
{ 
    // Loop & wait for work to arrive. Note that the condition variable must 
    // be locked before it can be waited on. You may also want to add 
    // another variable that gets checked every iteration so this thread can 
    // exit gracefully if need be. 
    while(1) 
    { 
     [workCondition lock]; 
     while(workQueue == NULL) 
     { 
      [workCondition wait]; 
      // The work queue should have something in it, but there are rare 
      // edge cases that can cause spurious signals. So double-check 
      // that it's not empty. 
     } 

     // Dequeue the work item & unlock the mutex so we don't block the 
     // main thread more than we have to 
     WorkItem *workItem = workQueue; 
     workQueue = workQueue->next; 
     if(workQueue == NULL) 
      workQueueTail = NULL; 
     [workCondition unlock]; 

     // Process the work item here 
     ... 
     free(workItem); // don't leak memory 
    } 
} 
+5

Scheint so, als würden Sie nur 'NSOperation' und' NSOperationQueue' neu erstellen ... –

+0

@Dave: Ich bin mit diesen Klassen nicht vertraut, aber beim Scannen der Dokumentation denke ich, dass das der Fall <_

+0

danke! Ich werde Dave auch einen Hinweis geben. – SpaceDog

1

Wenn Sie iOS4 und höher ausrichten können, sollen Blöcke mit Grand Central Dispatch asynch Warteschlange verwenden, die auf Hintergrund-Threads arbeiten, die die Warteschlange verwaltet ... oder für Abwärtskompatibilität, wie bereits erwähnt, verwenden Sie NSOperations innerhalb einer NSOperation-Warteschlange, um im Hintergrund Arbeitsschritte für Sie auszuführen. Sie können genau angeben, wie viele Hintergrundthreads Sie mit einer NSOperationQueue unterstützen möchten, wenn beide Vorgänge gleichzeitig ausgeführt werden müssen.