金沙国际官网_金沙国际平台登录

因为这个金沙国际官网_金沙国际平台登录网站与很多的大型澳门赌场都有合作,金沙国际官网_金沙国际平台登录尽职尽责,高效执行,保持好奇心,不断学习,追求卓越,点击进入金沙国际官网_金沙国际平台登录马上体验吧,所以现在也正式地开始了营业。

您的位置:金沙国际官网 > 编程 > greenlet使用介绍及实现原理,中的线程一

greenlet使用介绍及实现原理,中的线程一

发布时间:2020-01-05 04:46编辑:编程浏览(73)

    性能评估

    为了测试性能,我从Wikipedia获取一个网页,并将其中一部分内容写死到一个string的vector中。

    随后,我编写两个测试函数,第一个在两个循环中使用标准函数clock()并调用std::accumulate()和StringBuilder::ToString(),然后打印结果。

    void TestPerformance(const StringBuilder<wchar_t> &tested, const std::vector<std::wstring> &tested2) {
        const int loops = 500;
        clock_t start = clock(); // Give up some accuracy in exchange for platform independence.
        for (int i = 0; i < loops; ++i) {
            std::wstring accumulator;
            std::accumulate(tested2.begin(), tested2.end(), accumulator);
        }
        double secsAccumulate = (double) (clock() - start) / CLOCKS_PER_SEC;
    
        start = clock();
        for (int i = 0; i < loops; ++i) {
            std::wstring result2 = tested.ToString();
        }
        double secsBuilder = (double) (clock() - start) / CLOCKS_PER_SEC;
        using std::cout;
        using std::endl;
        cout << "Accumulate took " << secsAccumulate << " seconds, and ToString() took " << secsBuilder << " seconds."
                << " The relative speed improvement was " << ((secsAccumulate / secsBuilder) - 1) * 100 << "%"
                << endl;
    }
    

    第二个则使用更精确的Posix函数clock_gettime(),并测试StringBuilder::Join()。

    #ifdef __USE_POSIX199309
    
    // Thanks to <a href="http://www.guyrutenberg.com/2007/09/22/profiling-code-using-clock_gettime/">Guy Rutenberg</a>.
    timespec diff(timespec start, timespec end)
    {
        timespec temp;
        if ((end.tv_nsec-start.tv_nsec)<0) {
            temp.tv_sec = end.tv_sec-start.tv_sec-1;
            temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
        } else {
            temp.tv_sec = end.tv_sec-start.tv_sec;
            temp.tv_nsec = end.tv_nsec-start.tv_nsec;
        }
        return temp;
    }
    
    void AccurateTestPerformance(const StringBuilder<wchar_t> &tested, const std::vector<std::wstring> &tested2) {
        const int loops = 500;
        timespec time1, time2;
        // Don't forget to add -lrt to the g++ linker command line.
        ////////////////
        // Test std::accumulate()
        ////////////////
        clock_gettime(CLOCK_THREAD_CPUTIME_ID, &time1);
        for (int i = 0; i < loops; ++i) {
            std::wstring accumulator;
            std::accumulate(tested2.begin(), tested2.end(), accumulator);
        }
        clock_gettime(CLOCK_THREAD_CPUTIME_ID, &time2);
        using std::cout;
        using std::endl;
        timespec tsAccumulate =diff(time1,time2);
        cout << tsAccumulate.tv_sec << ":" <<  tsAccumulate.tv_nsec << endl;
        ////////////////
        // Test ToString()
        ////////////////
        clock_gettime(CLOCK_THREAD_CPUTIME_ID, &time1);
        for (int i = 0; i < loops; ++i) {
            std::wstring result2 = tested.ToString();
        }
        clock_gettime(CLOCK_THREAD_CPUTIME_ID, &time2);
        timespec tsToString =diff(time1,time2);
        cout << tsToString.tv_sec << ":" << tsToString.tv_nsec << endl;
        ////////////////
        // Test join()
        ////////////////
        clock_gettime(CLOCK_THREAD_CPUTIME_ID, &time1);
        for (int i = 0; i < loops; ++i) {
            std::wstring result3 = tested.Join(L",");
        }
        clock_gettime(CLOCK_THREAD_CPUTIME_ID, &time2);
        timespec tsJoin =diff(time1,time2);
        cout << tsJoin.tv_sec << ":" << tsJoin.tv_nsec << endl;
    
        ////////////////
        // Show results
        ////////////////
        double secsAccumulate = tsAccumulate.tv_sec + tsAccumulate.tv_nsec / 1000000000.0;
        double secsBuilder = tsToString.tv_sec + tsToString.tv_nsec / 1000000000.0;
            double secsJoin = tsJoin.tv_sec + tsJoin.tv_nsec / 1000000000.0;
        cout << "Accurate performance test:" << endl << "    Accumulate took " << secsAccumulate << " seconds, and ToString() took " << secsBuilder << " seconds." << endl
                << "    The relative speed improvement was " << ((secsAccumulate / secsBuilder) - 1) * 100 << "%" << endl <<
                 "     Join took " << secsJoin << " seconds."
                << endl;
    }
    #endif // def __USE_POSIX199309
    

    最后,通过一个main函数调用以上实现的两个函数,将结果显示在控制台,然后执行性能测试:一个用于调试配置。

    图片 1

    t另一个用于发行版本:

    图片 2

    看到这百分比没?垃圾邮件的发送量都不能达到这个级别!

    并发处理的技术背景

    并行化处理目前很受重视, 因为在很多时候,并行计算能大大的提高系统吞吐量,尤其在现在多核多处理器的时代, 所以像lisp这种古老的语言又被人们重新拿了起来, 函数式编程也越来越流行。 介绍一个python的并行处理的一个库: greenlet。 python 有一个非常有名的库叫做 stackless ,用来做并发处理, 主要是弄了个叫做tasklet的微线程的东西, 而greenlet 跟stackless的最大区别是, 他很轻量级?不够, 最大的区别是greenlet需要你自己来处理线程切换, 就是说,你需要自己指定现在执行哪个greenlet再执行哪个greenlet。

    一、同步委托

    我们平时所用的委托以同步居多,我们编写一个方法和相关委托进行演示:

    publicdelegatevoid DoSomethingDelegate(string name);
     //同步委托
    public static void Start1()
    {
        Console.WriteLine("this is primary thread");
        Console.WriteLine("main thread:{0},{1},{2}", Thread.CurrentThread.CurrentCulture, Thread.CurrentThread.Name, Thread.CurrentThread.ManagedThreadId);
        //DoSomethingDelegate del = new DoSomethingDelegate(Method1);
        //注意这里,简单起见还可以把一个方法名直接赋给一个委托类型
         DoSomethingDelegate del = Method1;
         del("this is delegate method");
     }
    //委托所关联的方法
     public static void Method1(string name)
     {
         Console.WriteLine("sub thread:           {0},{1},{2}", Thread.CurrentThread.CurrentCulture, Thread.CurrentThread.Name, Thread.CurrentThread.ManagedThreadId);
         Console.WriteLine(name);
         Thread.Sleep(TimeSpan.FromSeconds(3));
         Console.WriteLine("sub thread other things...");
      }
    

    我们分析下这个Start1()方法,首先显示了主线程相关的信息,然后定义了一个委托类型del,利用del(“this is delegate method”)执行Method1(string name)方法,由于是同步委托,所以主线程在执行到Thread.Sleep(TimeSpan.FromSeconds(3));处会暂时挂起,3秒后才继续执行,然后才返回到Start1()方法中继续执行。

    我们运行Start1()方法后看看执行顺序

    图片 3

    可以看到,运行结果是按主线程的执行顺序依次往下执行。

    鸣谢

    首先,我要为这段代码在Linux系统上做的精准分析感谢Rutenberg。

    多亏了Wikipedia,让“在指尖的信息”的梦想得以实现。

    最后,感谢你花时间阅读这篇文章。希望你喜欢它:不论如何,请分享您的意见。

    最近开始研究Python的并行开发技术,包括多线程,多进程,协程等。逐步整理了网上的一些资料,今天整理了一下greenlet相关的资料。

    三、异步委托详解

    刚才我们通过del.BeginInvoke(“this is delegate method”, null, null);这样就做到了异步调用,我们在编写代码中还有这样一种需求,如果你要进行异步调用,子线程执行的结果怎么返回给主线程呢?del.EndInvoke上场了!

    //异步委托得到返回值,实际上为了得到返回值,阻碍了主线程
     public static void Start3()
       {
         Console.WriteLine("main thread:{0},{1},{2}", Thread.CurrentThread.CurrentCulture, Thread.CurrentThread.Name, Thread.CurrentThread.ManagedThreadId);
          //DoSomethingDelegate del = new DoSomethingDelegate(Method1);
         DoSomethingDelegate2 del = Method2;
         IAsyncResult result=del.BeginInvoke("this is delegate method",null,null);
         string s = del.EndInvoke(result);
         Console.WriteLine("得到返回值:" + s);
         Console.WriteLine("main thread other things...");
       }//异步委托所调用的方法,注意此方法有返回值 
     public static string  Method2(string name)
       {
           Console.WriteLine("sub thread:{0},{1},{2}", Thread.CurrentThread.CurrentCulture, Thread.CurrentThread.Name, Thread.CurrentThread.ManagedThreadId);
           Console.WriteLine(name);
           Thread.Sleep(TimeSpan.FromSeconds(3));
           Console.WriteLine("sub thread other things...");
           return "返回委托值";
       }
    

    从实例代码中我们可以看到,我们为了得到异步方法的返回值写了这么两行代码:

    IAsyncResult result=del.BeginInvoke("this is delegate method",null,null);
    string s = del.EndInvoke(result);
    

    图片 4

    我们查看执行结果:由运行结果可以看到,屏幕输出了返回值,但是Method2(string name)方法并没有被异步执行到!原因在于string s = del.EndInvoke(result);这句阻碍了主线程的继续执行,等子线程返回值后赋给s后,主线程才继续执行。这样写的后果就是:为了得到返回值,阻碍了主线程

    我们刚才执行异步委托都是通过下面的代码来完成的

    IAsyncResult result=del.BeginInvoke("this is delegate method",null,null);
    

    我们将BeginInvoke方法的第二个和第三个参数都设置为了null,我们现在来看看这两个参数的作用!第二个参数AsyncCallBack  callback,这个参数实际上是一个回调委托,我们看此委托的定义:

    public delegate void AsyncCallback(IAsyncResult ar);
    

    什么是回调方法?就是说委托所调用的方法执行完毕后自动执行的方法,即上面的Method2(string name)方法被异步执行结束后所调用的方法。于是我们在定义一个跟AsyncCallback委托匹配的方法:

    public static void CallBack(IAsyncResult result)
      {
        DoSomethingDelegate2 del = result.AsyncState as DoSomethingDelegate2;
        string s = del.EndInvoke(result);
        Console.WriteLine("得到返回值:" + s);
      }
    
    public static void Start4()
     {
        Console.WriteLine("main thread:{0},{1},{2}", Thread.CurrentThread.CurrentCulture, Thread.CurrentThread.Name, Thread.CurrentThread.ManagedThreadId);
        DoSomethingDelegate2 del = Method2;
        AsyncCallback callBack = CallBack;
         del.BeginInvoke("this is delegate method", callBack, del);
        Console.WriteLine("main thread other things...");
      }
    
    public static string  Method2(string name)
      {
         Console.WriteLine("sub thread:{0},{1},{2}", Thread.CurrentThread.CurrentCulture, Thread.CurrentThread.Name, Thread.CurrentThread.ManagedThreadId);
         Console.WriteLine(name);
         Thread.Sleep(TimeSpan.FromSeconds(3));
         Console.WriteLine("sub thread other things...");
         return "返回委托值";
      }
    

    从上面的代码可以看出,在CallBack方法中我们得到了Method2(string name)方法的返回值。并且整个过程是异步执行的!请看运行结果:

    图片 5

    为了得到异步方法的返回值还可以这么做:

    public static void Start4()
       {
          Console.WriteLine("main thread:{0},{1},{2}", Thread.CurrentThread.CurrentCulture, Thread.CurrentThread.Name, Thread.CurrentThread.ManagedThreadId);
          DoSomethingDelegate2 del = Method2;
          //另一种实现方法
          del.BeginInvoke("this is delegate method", CallBack2, null);
          Console.WriteLine("main thread other things...");
       }
    
    public static void CallBack2(IAsyncResult result)
     {
        AsyncResult ar = result as AsyncResult;
        DoSomethingDelegate2 del = ar.AsyncDelegate as DoSomethingDelegate2;
        string s=del.EndInvoke(ar);
        Console.WriteLine("得到返回值:" + s);
     }
    

    这段代码的运行效果跟上面是一样的,只不过写法不同而已!

    有趣的部分

    函数ToString()使用std::string::reserve()来实现最小化再分配。下面你可以看到一个性能测试的结果。

    函数join()使用std::accumulate(),和一个已经为首个操作数预留内存的自定义函数。

    你可能会问,为什么StringBuilder::m_Data用std::list而不是std::vector?除非你有一个用其他容器的好理由,通常都是使用std::vector。

    好吧,我(这样做)有两个原因:

    1. 字符串总是会附加到一个容器的末尾。std::list允许在不需要内存再分配的情况下这样做;因为vector是使用一个连续的内存块实现的,每用一个就可能导致内存再分配。

    2. std::list对顺序存取相当有利,而且在m_Data上所做的唯一存取操作也是顺序的。

    你可以建议同时测试这两种实现的性能和内存占用情况,然后选择其中一个。

    总结一下:

    1)多进程能够利用多核优势,但是进程间通信比较麻烦,另外,进程数目的增加会使性能下降,进程切换的成本较高。程序流程复杂度相对I/O多路复用要低。

    2)I/O多路复用是在一个进程内部处理多个逻辑流程,不用进行进程切换,性能较高,另外流程间共享信息简单。但是无法利用多核优势,另外,程序流程被事件处理切割成一个个小块,程序比较复杂,难于理解。

    3)线程运行在一个进程内部,由操作系统调度,切换成本较低,另外,他们共享进程的虚拟地址空间,线程间共享信息简单。但是线程安全问题导致线程学习曲线陡峭,而且易出错。

    4)协程有编程语言提供,由程序员控制进行切换,所以没有线程安全问题,可以用来处理状态机,并发请求等。但是无法利用多核优势。

    上面的四种方案可以配合使用,我比较看好的是进程+协程的模式。

    二、异步委托

    //异步委托
    public static void Start2()
    {
        Console.WriteLine("main thread:{0},{1},{2}", Thread.CurrentThread.CurrentCulture, Thread.CurrentThread.Name, Thread.CurrentThread.ManagedThreadId);
        //DoSomethingDelegate del = new DoSomethingDelegate(Method1);
        DoSomethingDelegate del = Method1;
        del.BeginInvoke("this is delegate method", null, null);
        Console.WriteLine("main thread other things...");
    }
    

    此次我们利用委托的BeginInvoke方法进行方法调用,BeginInvoke的方法签名如下:

    IAsyncResult  DoSomethingDelegate.BeginInvoke(string name,AsyncCallBack  callback,object @object)
    

    那么利用BeginInvoke进行方法调用的结果如何呢?如结果显示,BeginInvoke调用的方法有一个子线程去调用,主线程没有被执行到,Thread.Sleep(TimeSpan.FromSeconds(3));这个方法,也就没有被挂起线程。

    图片 6

    本文由金沙国际官网发布于编程,转载请注明出处:greenlet使用介绍及实现原理,中的线程一

    关键词:

上一篇:没有了

下一篇:没有了