2009-06-10 15 views
5

Questo ha qualche equivalente in c?Resa in C#

+2

nemmeno vicino! –

+0

Perché hai bisogno di rendimento? Se si dispone di un array, è possibile solo iterarlo. Il rendimento è rilevante per IEnumerables, che generalmente useresti in una situazione 'foreach'. Dal momento che non puoi "forzare" perché dovresti creare un "rendimento"? – DevinB

risposta

2

No. Su Windows, tuttavia, è possibile utilizzare le fibre per ottenere un effetto simile.

7

Mentre C non ha lo stesso concetto di rendimento per quanto riguarda enumerare su un insieme che ha la capacità di creare coroutine e fibre.

Ecco alcuni articoli di Wikipedia, che potrebbero essere di interesse:

http://en.wikipedia.org/wiki/Setcontext http://en.wikipedia.org/wiki/Setjmp/longjmp

+0

Penso che questo è di gran lunga troppo complicato. La metodologia migliore sarebbe quella di creare solo una struct che ha avuto una variabile yieldindex e l'array in esso, quindi incrementare l'indice ogni volta che si farebbe 'rendimento'. In questo modo il tuo "rendimento" tira semplicemente il valore dell'array dal punto yieldindex. – DevinB

+1

Non sto dicendo che non è complicato, solo che questo è il C equivalente. Ci sono molti modi per risolvere questo problema ... per questo scriviamo software =) – jonnii

1

No. Tuttavia, è possibile ottenere simili effetti in C con l'uso di setjmp, longjmp, ma è molto difficile.

11

Il rendimento viene implementato dal compilatore come una classe personalizzata che implementa una macchina a stati. Anche se non è possibile ottenere la sintassi con la stessa facilità (a meno che non si utilizzi il metodo fibra specificato in precedenza) è possibile replicare i risultati da soli in modo piuttosto semplice, anche se è piuttosto noioso. Ecco come (vi mostrerò in C#, dovrete fare la cosa appropriata in C++ a seconda del tipo in uso):

Supponendo che il seguente codice:

public IEnumerable<T> GetOddStrings(
    IEnumerable<IEnumerable<string>> stringCollections) 
{ 
    foreach(var stringCollection in stringCollections) 
     foreach(var str in stringCollection) 
     { 
     if(str.Length %2 != 0) yield return str; 
     if(str.Length == 42) yield break; // 42 is BAD! Stop immediately 
     } 
} 

1) Svolgere tutte foreach metodi in enumeratore esplicito chiamate:

public IEnumerable<T> GetOddStrings(
    IEnumerable<IEnumerable<string>> stringCollections) 
{ 
    var firstEnumerator = stringCollection.GetEnumerator(); 
    while(firstEnumerator.MoveNext()) 
    { 
    var secondEnumerator = firstEnumerator.Current.GetEnumerator(); 
    while(secondEnumerator.MoveNext()) 
    { 
     var str= secondEnumerator.Current; 
     if(str.Length %2 != 0) yield return str; 
     if(str.Length == 42) yield break; 
    } 
    } 
} 

2) Spostare tutte le variabili locali alla parte superiore del metodo:

public IEnumerable<T> GetOddStrings(
    IEnumerable<IEnumerable<string>> stringCollections) 
{ 
    IEnumerator<IEnumerable<string>> firstEnumerator; 
    IEnumerator<string> secondEnumerator; 
    string str; 

    firstEnumerator = stringCollections.GetEnumerator(); 
    while(firstEnumerator.MoveNext()) 
    { 
    secondEnumerator = firstEnumerator.Current.GetEnumerator(); 
    while(secondEnumerator.MoveNext()) 
    { 
     str= secondEnumerator.Current; 
     if(str.Length %2 != 0) yield return str; 
     if(str.Length == 42) yield break; 
    } 
    } 
} 

3) Passare a un costrutto di loop con un'istruzione switch nidificata.
a) Modificare lo stato e continuare il ciclo per ogni rendimento restituito. b) Invertire se condizioni a c) Interruzione del rendimento per ogni condizione di uscita (di seguito si inverte il valore if).

public IEnumerable<T> GetOddStrings(
    IEnumerable<IEnumerable<string>> stringCollections) 
{ 
    IEnumerator<IEnumerable<string>> firstEnumerator; 
    IEnumerator<string> secondEnumerator; 
    string str; 
    int state = 0; 

    while(true) 
    { 
    switch(state) 
    { 
     case 0: 
     firstEnumerator = stringCollections.GetEnumerator(); 
     // This could be "yield break" but I want to show how you 
     // could split ifs with significant code in the else 
     if(!firstEnumerator.MoveNext()) 
     { 
      state = 1; 
      continue; 
     } 

     secondEnumerator = firstEnumerator.Current; 
     if(!secondEnumerator.MoveNext) continue; 
     state = 2; 
     if(str.Length %2 != 0) yield return str; 
     continue; 

     case 1: 
     yield break; 

     case 2: 
     if(str.Length == 42) yield break; 
     state = 0; 
     continue; 
    } 
    } 
} 

4) Spostare in una classe e restituire la classe da metodo: a) le pause di rendimento diventano "return false;" b) i resi di rendimento diventano "this.Current = ??; return true;"

public IEnumerable<T> GetOddStrings(
    IEnumerable<IEnumerable<string>> stringCollections) 
{ 
    return new OddStringEnumerable(stringCollections); 
} 

private class OddStringEnumerable : IEnumerable<string> 
{ 
    IEnumerable<IEnumerable<string>> stringCollections; 
    IEnumerator<IEnumerable<string>> firstEnumerator; 
    IEnumerator<string> secondEnumerator; 
    string str; 
    int state; 

    public OddStringEnumerable(IEnumerable<IEnumerable<string>> stringCollections) 
    { 
    this.stringCollections = stringCollections; 
    } 

    public string Current { get; private set; } 

    public bool MoveNext() 
    { 
    while(true) 
    { 
     switch(state) 
     { 
     case 0: 
      firstEnumerator = this.stringCollections.GetEnumerator(); 
      if(!this.firstEnumerator.MoveNext()) 
      { 
      this.state = 1; 
      continue; 
      } 

      this.secondEnumerator = this.firstEnumerator.Current; 
      if(!secondEnumerator.MoveNext) continue; 

      this.state = 2; 
      if(str.Length %2 != 0) 
      { 
      this.Current = str; 
      return true; 
      } 
      continue; 

     case 1: 
      return false; 

     case 2: 
      if(str.Length == 42) return false; 
      this.state = 0; 
      continue; 
     } 
    } 
    } 
} 

5) Ottimizzare come appropriato.

5

Coroutines in C utilizza alcuni hackery del preprocessore, ma implementa un abbastanza naturale (rispetto a qualsiasi altra cosa in C) yield.

Mentre devi scrivere questo in Python:

"""This is actually a built-in function. 
def range(start, stop, step): 
    i = start 
    while i < stop: 
     yield i 
     i = i + step 
""" 

if __name__ == '__main__': 
    import sys 
    start = int(sys.argv[1]) if len(sys.argv) > 2 else 0 
    stop = int(sys.argv[2]) if len(sys.argv) > 2 else int(sys.argv[1]) 
    step = int(sys.argv[3]) if len(sys.argv) > 3 else 1 
    for i in range(start, stop, step): 
     print i, 
    print 

coroutine.h vi permette di scrivere questo in C:

#include <coroutine.h> 
#include <stdio.h> 

int range(int start, int stop, int step) { 
    static int i; 

    scrBegin; 
    for (i = start; i < stop; i += step) 
     scrReturn(i); 
    scrFinish(start - 1); 
} 

int main(int argc, char **argv) { 
    int start, stop, step, i; 

    start = argc > 2 ? atoi(argv[1]) : 0; 
    stop = argc > 2 ? atoi(argv[2]) : atoi(argv[1]); 
    step = argc > 3 ? atoi(argv[3]) : 1; 

    while ((i = range(start, stop, step)) >= start) 
     printf("%d ", i); 
    printf("\n"); 
} 
 
$ cc range.c 
$ ./a.out 10 
0 1 2 3 4 5 6 7 8 9 

Per qualcosa di più complesso e che richiede rientranza, il Hamming numbers in Python :

def hamming(): 
    yield 1 

    i2 = (2*x for x in hamming()) 
    i3 = (3*x for x in hamming()) 
    i5 = (5*x for x in hamming()) 

    m2, m3, m5 = i2.next(), i3.next(), i5.next() 

    while True: 
     if m2 < m3: 
      if m2 < m5: 
       yield m2 
       m2 = i2.next() 
      else: 
       if m2 > m5: yield m5 
       m5 = i5.next() 
     elif m2 == m3: m3 = i3.next() 
     elif m3 < m5: 
      yield m3 
      m3 = i3.next() 
     else: 
      if m3 > m5: yield m5 
      m5 = i5.next() 

if __name__ == '__main__': 
    import sys 
    it = hamming() 
    for i in range(str(sys.argv[1]) if len(sys.argv) > 1 else 25): 
     print it.next(), 
    print 

e C:

#include <coroutine.h> 
#include <stdio.h> 

int hamming(ccrContParam) { 
    ccrBeginContext; 
    ccrContext z[3]; 
    int m2, m3, m5; 
    ccrEndContext(state); 

    ccrBegin(state); 
    state->z[0] = state->z[1] = state->z[2] = 0; 
    ccrReturn(1); 

#define m2_next (2*hamming(&state->z[0])) 
#define m3_next (3*hamming(&state->z[1])) 
#define m5_next (5*hamming(&state->z[2])) 

    state->m2 = m2_next, state->m3 = m3_next, state->m5 = m5_next; 

    while (1) { 
     if (state->m2 < state->m3) { 
      if (state->m2 < state->m5) { 
       ccrReturn(state->m2); 
       state->m2 = m2_next; 
      } else { 
       if (state->m2 > state->m5) ccrReturn(state->m5); 
       state->m5 = m5_next; 
      } 
     } else if (state->m2 == state->m3) state->m3 = m3_next; 
     else if (state->m3 < state->m5) { 
      ccrReturn(state->m3); 
      state->m3 = m3_next; 
     } else { 
      if (state->m3 > state->m5) ccrReturn(state->m5); 
      state->m5 = m5_next; 
     } 
    } 
    ccrFinish(-1); 
} 

int main(int argc, char **argv) { 
    int count = argc > 1 ? atoi(argv[1]) : 25, i; 
    ccrContext z = 0; 

    for (i = 0; i < count; i++) 
     printf("%d ", hamming(&z)); 
    printf("\n"); 
} 
 
$ cc hamming.c 
$ ./a.out 
1 2 3 4 5 6 8 9 10 12 15 16 18 20 24 25 27 30 32 36 40 45 48 50 54 
1

in C# rendimenti semplifica la creazione di IEnumberables per una collezione.

In C++ è necessario utilizzare iteratori STL.