从125ms到11ms,记一次关键字检测过滤服务的优化 -python and Pythonnet

接上文:《高效的的关键字查找和检测(哈希表和Trie前缀树和FastCheck)在实际使用中的性能

动态语言是很慢的,它更多的是为了提高开发效率,这里的关键字过滤算法在生产环境中用原生python达到125ms 2千万字/每秒已经够用了。那么是不是可以适当的优化再快一点?

Cython,没事cython一下,带你飞

cython能把大部分python代码改为静态的c实现,甚至你可以混合c和python一起写。不过现实是大部分的pythoner如果碰到性能问题要么用go要么就是用csharp,很少去写cython。下面是用cython编译后的测试结果:

提升39%,马马虎虎,也可能跟Tool.Good源码的实现有关。此时文本的处理量已经到了3400万/每秒,用是够用了,那么能不能更快一点?

C# 是时候展现你的实力了

Tool.Good作者明显是一位纯粹的csharpner, 既然已经实现了3亿效率的代码为什么不拿来用呢。这里作为对比,我先写了一个参照的测试程序,测试环境与前文相同。代码如下

using System;
using ToolGood.Words;
namespace KeywordTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var stopwatch = System.Diagnostics.Stopwatch.StartNew();
           
            string post = System.IO.File.ReadAllText(@"D:\Projects\Opensource\ToolGood.Words\csharp\KeywordTest\sample_post");

            string[] spams = System.IO.File.ReadAllLines(@"D:\Projects\Opensource\ToolGood.Words\csharp\KeywordTest\SpamWordsCN.min.txt");

            StringSearch iwords = new StringSearch();
            iwords.SetKeywords(spams);
            stopwatch.Start();
            for (var i = 0; i < 500; i++)
            { var f = iwords.FindFirst(post); }

            stopwatch.Stop();
            var s = stopwatch.ElapsedMilliseconds;
            Console.WriteLine("测试用时(ms):" + s);
        }
    }
}
Customer Retention: 3 Easy Ways to WOW Your Customers | Car People Marketing
此时的表情

Csharp性能都这样了更别说C了,那么为什么能比cython快那么多呢。这里分两部分原因,一部分性能浪费在python和c的交互上,另一部分在cython编译时的类型推断和生成的代码优化不够,大量使用的还是pure python。咱不纠结这个,手头有这么快的csharp不用简直浪费,一脚踢走cython,黏上csharp,让它飞的更高~

接福啦- 简书

Pythonnet 闪亮登场

这可是个好东西,.net基金会项目,官方身份,神秘可靠。有了它使得python和.net交互变得简单。这里需要一提的是目前稳定版2.5.2还只支持.net 4.0,至于.net core 3和.net5需要手动安装master分支上的3.0.0dev,实现方式 也有所不同,下面是代码:

def test2():

    from clr_loader import get_coreclr
    from pythonnet import set_runtime

    rt = get_coreclr("./runtimeconfig.json")
    set_runtime(rt)
    import  clr
    clr.AddReference('ToolGood.Words')

    import clr
    from System import String
    from ToolGood.Words import StringSearch
    stringSearch=StringSearch()

    with  open('./sample_post',encoding='utf-8') as f:
        test_post = f.read()
    from System.Collections.Generic import List
    spam_words=List[String]()
    with open('././SpamWordsCN.min.txt',encoding='utf-8') as f:
        for line in [line.rstrip() for line in f]:
            spam_words.Add(String(line))

    stringSearch.SetKeywords(spam_words)
    import time
    start = time.time()
    times = 500
    while times > 0:
        f = stringSearch.FindFirst(test_post)
        times -= 1
    end = time.time()
    print('程序运行时间:%s毫秒' % ((end - start) * 1000))
{
  "runtimeOptions": {
    "tfm": "net5.0",
    "framework": {
      "name": "Microsoft.NETCore.App",
      "version": "5.0.2"
    }
  }
}
4种吃了会让人开心的食物- 每日头条
此时的心情

事实上如果增加压力还能提高性能,因为交互部分压力越大性价比越高。此时的处理速度已经到了2.5亿/每秒。那么能不能再快点?烦不烦,其实也不烦,生产中怎么可能不并行呢,动不动八核十几核的,线程再来double一下,妥妥的几十亿。

为什么不直接用csharp直接做服务

当然可以,如果负载确实高换纯csharp顶上,还不够再换go,还不够把分布式也弄上。但现实是高负载的需求可能永远不会到来,为什么不把时间省下来去做更有意义的事呢?

发表评论

您的电子邮箱地址不会被公开。