Coroutine demo source

后端 未结 3 1034
盖世英雄少女心
盖世英雄少女心 2021-01-07 02:54

Here\'s an example of a program, where coroutines really help to simplify the algorithm - imho its hardly possible to implement otherwise. I also tried to choose a useful ta

3条回答
  •  隐瞒了意图╮
    2021-01-07 03:13

    Ok, here's what I actually asked about (see [1]) - the trick to statically call a function from child class. tl;dr is apparently a mighty power, so here's your readable standard coroutine fibonacci generator this time. There's a small difference though - we don't really need coroutines to generate these numbers, but its really hard (if possible) to make a faster implementation of my first program without coroutines.

    #include 
    #include 
    #include 
    
    // without noinline some compilers tend to allocate the array before setjmp()
    #ifdef __GNUC__
     #define NOINLINE __attribute__((noinline))
    #else
     #define NOINLINE __declspec(noinline)
    #endif
    
    enum{ STKPAD=1<<16 };
    struct coroutine {
      volatile unsigned state;
      jmp_buf PointA, PointB;
      void yield( int value ) { if( setjmp(PointB)==0 ) { state=value; longjmp(PointA,value); } }
      template  NOINLINE void call_do_process() {
        char stktmp[STKPAD]; state=ptrdiff_t(stktmp); ((T*)this)->do_process();
      }
      template  unsigned coro_process( T* ) {
        if( setjmp(PointA)==0 ) if( state ) longjmp(PointB,3); else call_do_process();
        return state;
      }
    };
    
    struct fibonacci : coroutine {
    
      void do_process( void ) {
        unsigned a=0,b=1;
        while(1) {
          yield( b );
          b = b + a;
          a = b - a;
        }
      }
    
      unsigned get( void ) {
        return coro_process(this); 
      }
    
    } F;
    
    int main( int argc, char** argv ) {
    
      for( int i=0; i<20; i++ ) {
        printf( "%i ", F.get() );
      } printf( "\n" );
    
      return 0;
    }
    

    And since Jerry Coffin's alternative version still fails to produce sensible results, here're some simpler stream benchmarks. Its a pity, as I'd expect it to be even slower with iterators.

    In fact I've tested all kinds of approaches with arithmetic coders - plain getc/putc, virtual methods, plain functions pointers, iterator-like classes, and its clear that there's a large difference. For now, coroutines proved to be the best way for this - there's no complex logic encapsulated into byte i/o calls (unlike iterators), and the processing doesn't have to care about i/o details. Sure, there're even further optimizations, but I really only tried to demonstrate the benefits of coroutine approach here...

    #define _CRT_SECURE_NO_DEPRECATE
    #define _CRT_DISABLE_PERFCRIT_LOCKS
    
    #include 
    #include 
    #include 
    
    int main( int argc, char** argv ) {
      if( argc<3 ) return 1;
    
      { 
        clock_t start = clock();
        FILE* f = fopen( argv[1], "rb" ); if( f==0 ) return 2;
        FILE* g = fopen( argv[2], "wb" ); if( g==0 ) return 3;
        while(1) {
          int c = getc(f);
          if( c<0 ) break;
          putc(c,g);
        }
        fclose(f);
        fclose(g);
        clock_t stop = clock();
        printf( "            File copy via stdio getc/putc - %7.3fs\n", float(stop-start)/CLOCKS_PER_SEC );
      }
    
      {
        clock_t start = clock();
        FILE* f = fopen( argv[1], "rb" ); if( f==0 ) return 2;
        FILE* g = fopen( argv[2], "wb" ); if( g==0 ) return 3;
        while(1) {
          static char buf[1<<16];
          int l = fread( buf, 1,sizeof(buf), f ); if( l<=0 ) break;
          fwrite( buf, 1,l, g ); if( l
    ----- 100,000,000 byte file ----- 
    [ GCC 4.5 ]
                File copy via stdio getc/putc -   0.546s
         File copy via stdio 64k fread/fwrite -   0.188s
    File copy via ifstream::get/ofstream::put -  10.578s
    
    [ IntelC 11.1 / VS 2005 ]
                File copy via stdio getc/putc -   0.500s
         File copy via stdio 64k fread/fwrite -   0.156s
    File copy via ifstream::get/ofstream::put -  14.656s
    
    [ MSC 14.0 / VS 2005 ]
                File copy via stdio getc/putc -   0.609s
         File copy via stdio 64k fread/fwrite -   0.156s
    File copy via ifstream::get/ofstream::put -  19.063s
    
    ----- 1,000,000,000 byte file ----- 
    [ GCC 4.5 ]
                File copy via stdio getc/putc -   7.468s
         File copy via stdio 64k fread/fwrite -   1.828s
    File copy via ifstream::get/ofstream::put - 109.891s
    
    [ IntelC 11.1 / VS 2005 ]
                File copy via stdio getc/putc -   6.718s
         File copy via stdio 64k fread/fwrite -   1.672s
    File copy via ifstream::get/ofstream::put - 145.500s
    
    [ MSC 14.0 / VS 2005 ]
                File copy via stdio getc/putc -   6.453s
         File copy via stdio 64k fread/fwrite -   1.609s
    File copy via ifstream::get/ofstream::put - 191.031s
    

提交回复
热议问题