• 使用 Nginx+Gunicorn 部署 Flask,with venv+systemd

    记录一下我的部署过程。

    Flask

    文件为 /root/myproject/application.py,其中的 Flask 实例为

    app = Flask(__name__)

    Gunicorn

    /root/myproject/ 中新建一个虚拟环境 venv 并激活虚拟环境,使用 pip 安装 Flask 等模块。然后安装 gunicorn:

    pip install gunicorn

    装好之后,执行命令:

    gunicorn --bind 127.0.0.1:8000 application:app   # application为文件名 app为实例名

    http://127.0.0.1:8000 应该是可以访问的。(服务器可能需要做一下端口转发,不然就绑定 0.0.0.0)

    Systemd

    我希望服务器重启后,也可以自动启动 web server。

    新建 /usr/lib/systemd/system/gunicorn.service,内容如下:

    [Unit]
    Description=gunicorn daemon
    After=network.target
    
    [Service]
    WorkingDirectory=/root/myproject
    ExecStart=/root/myproject/venv/bin/gunicorn -w 1 --bind 127.0.0.1:8000 application:app
    PrivateTmp=true
    Environment=key=value
    
    [Install]
    WantedBy=multi-user.target

    然后执行 systemctl enable gunicorn,重启一下服务器,之后执行 systemctl status gunicorn 确认服务正常启动。这里备注一下“Environment=key=value”这一行,systemd 启动的服务是不带环境变量的,被这个坑了好久🤣。

    Nginx

    最后,我使用 nginx 进行转发,和实现 https 访问。修改 /etc/nginx/conf.d/default.conf

    server {
        listen       443 ssl;
        server_name  myproject;
    
        access_log  /var/log/nginx/access.log;
        error_log   /var/log/nginx/error.log;
    
        location / {
            proxy_pass http://127.0.0.1:8000;
            proxy_redirect     off;
            proxy_set_header   Host                $host:$server_port;
            proxy_set_header   X-Real-IP           $remote_addr;
            proxy_set_header   X-Forwarded-For     $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Proto   $scheme;
         }
    
        ssl_certificate     /path/yourssl.cer;
        ssl_certificate_key /path/yourssl.key;
        ssl_session_timeout  5m;
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
        ssl_protocols TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
    }

    最后,测试一下 https://server_ip 看看能不能访问。

  • 阿里云轻量应用服务器初步体验

    今年过年特别有空,来体验一下阿里云的轻量应用服务器。它境外的服务器,24元/月起,相比 ECS 和各种友商,是算便宜的(还是我没有找到更便宜的?)。体验好的话,本站也考虑搬过去。

    先大概了解了一下,有人说它是基于 ECS 的 T5突发性能实例。我这里访问量不大,应该没问题。也有人说它可用性 <95%,这个就要自己试一下了。

    购买的流程比 ECS 简单很多,最主要的是选择 “应用镜像”或“系统镜像”。应用镜像主要是一些网站了,WordPress、ECShop、phpwind等;系统镜像就和 ECS 的差不多,基本上就是系统,再给你自带阿里云的一些软件,云盾、监控什么的。整体流程 1 分钟可以走完。

    阅读更多…
  • Python 性能分析之每行耗时 line_profiler

    大家都知道,Python 的运算性能不是很强,所以才有了那么多用 C/C++ 来计算的第三方 Python 包,还有各种各样的加速实践。

    那么,应该加速哪些代码呢?我之前一般用自带的 cProfile,然而它的输出确实不是太好看,夹杂了非常多无用的信息。

    最近才发现了 line_profiler 这个第三方扩展,用起来比 cProfile 直观很多。

    安装

    pip install line-profiler

    安装需要编译器。如果在 Windows 平台,需要自行先安装 C++ 编译器。如果不想装麻烦的 VC++,可以转而在 这里 下载别人编译好的 .whl 安装包。在 Linux/Mac 上面就简单很多,编译环境肯定有的。

    使用

    在需要 profile 的函数前,加上”@profile”,例如下面的 xxxxxx.py:

    @profile
    def main():
        l = [i for i in range(10000)]
        s = set(l)
    
        for _ in range(1000):
            if 9876 in l:
                pass
            if 9876 in s:
                pass
    
    if __name__ == '__main__':
        main()

    这个”@profile”只是一个标记,不是 Python 的语句,所以会导致代码不能直接运行,只能用专门的方法运行(下面有),这不是太方便(目前的版本是这样)。

    经过一点使用,了解到 @profile 的用法有一点限制,不可以对 class 打标签,但是可以打在 class 的方法上;子函数也可以用;并且可以同时 profile 多个函数 。

    然后,运行:

    kernprof -v -l xxxxxx.py

    我们就得到了结果:

    Wrote profile results to xxxxxx.py.lprof
    Timer unit: 1e-06 s
    
    Total time: 0.076552 s
    File: xxxxxx.py
    Function: main at line 2
    
    Line #      Hits         Time  Per Hit   % Time  Line Contents
    ==============================================================
         2                                           @profile
         3                                           def main():
         4         1        965.0    965.0      1.3      l = [i for i in range(10000)]
         5         1        792.0    792.0      1.0      s = set(l)
         6
         7      1001       1278.0      1.3      1.7      for _ in range(1000):
         8      1000      71133.0     71.1     92.9          if 9876 in l:
         9                                                       pass
        10      1000       1297.0      1.3      1.7          if 9876 in s:
        11      1000       1087.0      1.1      1.4              pass

    就知道应该着重优化哪部分了。

    参考

    1. https://github.com/rkern/line_profiler

  • Python 多进程共享内存、NumPy 数组 | Sharing NumPy Array When Using Python Multiprocessing

    背景

    当前的项目需要对大型 numpy 数组进行各种运算(不是深度学习的那种运算),实践发现只开一个 python 进程时,只能使用一个 CPU 核心。所以考虑使用 multiprocessing 模块进行多进程运算。

    但是,问题也很明显:用的是 multiprocessing.pool,如果我的 pool 的 size 是 4,一个 GB 级的 ndarray 传给 pool,会复制 4 份到每一个子进程。这首先会在传输时花时间做相应的 pickle 和 unpickle 操作;更重要的是,这坨数据会在内存里复制 4 份——这直接导致能处理的最大数据大小缩小了四分之三。

    本文使用的 Python 版本为 3.6 / 3.7,Windows 系统。
    在 3.8 版本中,新加入了 multiprocessing.shared_memory 模块,应该能简化这个问题。但是目前为止,项目使用的部分包还不支持 3.8,所以仍需要在旧版本中解决这个问题。

    Value 与 Array

    在 multiprocessing 包中,提供了一些可共享的对象:Value、Array、RawValue 与 RawArray。基本上,前者没有 Raw 的,可以加锁以进行进程间同步,后面 Raw 的没有锁。项目中用到的 numpy 数组都是只读的,子进程只需要读不需要写,所以选择使用 RawArray。

    阅读更多…
  • 2019 Godaddy 域名转到 Namesilo 记录

    前言

    又是我一年一度的域名续费时间。我的 .com 域名在 Godaddy 已经快10年了,今年的续费又是没有优惠——$15 USD起。即使用上了“印度卢比大法”(把支付货币改为印度卢比),续费的价格也要 800 印度卢比,也就是大约 ¥80 人民币,或 $11 USD。

    是不是 Godaddy 的广告打太多,导致其运营成本上升,羊毛出在羊身上?我专门找回了当年的订单记录,我在2014年续费的价格是 $9 USD,2011年甚至只用了 $7.xx。从2015年起,我的续费价格就没有低于 $10 了。

    相比之下,Namesilo 只需要不到 $9 USD,想想还是转吧。下面是流程介绍。

    阅读更多…
  • 通过 SSH 反向代理访问内网服务

    最近用到,简要记录下来。具体可参考文末的相关链接。

    前言

    首先,什么是反向代理?下图很清晰地解释了它与正向代理的区别。

    反向代理的模式,可以使 client 访问与 proxy 同一局域网的 server。且 client 只知道自己在访问 proxy,而不知道真正提供服务的是 server。

    阅读更多…
  • 记一次久违的重装Win10系统

    平时都有一个工具U盘,里面有各种工具,电脑有问题一般都能解决。前几天遇到一台电脑系统崩了,但我的工具U盘不在身边,另外是太久没遇到了,开始竟有点不知所措。后来尝试修复系统,不成功,唯有重装。在此记录一下过程,以备忘。

    一个新的引导设备还是需要的,例如一个空的U盘。

    先搞个 WinPE 吧。首先下载了 grub4dos,解压 grldr 等文件到根目录。然后忘了怎么写入 MBR 使U盘变成可启动。 grub4dos 里面有文档,阅读文档后发现其自带的 bootlace.com 可以完成这一任务,它可以在 DOS/Linux 下运行。我刚好有能用的 Linux 系统,运行

    sudo ./bootlace.com /dev/sdb1  # 根据实际情况修改路径

    即可。事后想起来用 bootice 会更方便。

    可以启动,写好 grub4dos 的 menu.lst 配置文件,把 WinPE 的 iso 文件放好,我用的是 wingwy-pe5.1-v1f1.iso(MD5为7F931189D41FE2B65FA07BE1B970F3A8),保证纯净、没有恶意代码。

    进了 PE 系统,mount Win10 的 iso,发现安装的时候又遇到了“我们无法创建新的分区,也找不到现有的分区”问题。改用 windows media creation tool 来创建一个最纯正的安装U盘,还是一样的问题。

    记得这个问题可以用安装器来解决。但是我还是选择先百度一波。发现可以用硬盘安装法,即提取 iso 的 boot文件夹、source文件夹、bootmgr文件到根目录即可。

    安装之前还想怎么备份原来的激活。百度告诉我,不需要备份,不需要填 key,可以直接安装。事实证明确实如此。

    搞了半天,最后发现其实只需要直接做硬盘安装,就完事了🤣。如果对于一个新的硬盘,在安装之前还需要另外用 bootice 设置一下 bootmgr 的引导,就可以安装了。

  • 用 Numba 加速你的 Python 代码,性能轻松大提升

    Numba 简介

    Numba 是 Python 的一个 JIT (just-in-time) 编译器,最适用于 NumPy 数组、函数,以及 Python 循环。基本上,用法就是给原来的 Python 函数加一个修饰器,当运行到经 Numba 修饰的函数时,它会被编译为机器码,之后再调用时,就能以机器码的速度来执行了。

    按我上手使用的经验来看,Numba 对原代码的改动不是太大,对能加速的部分,加速效果明显;对不支持的加速的 Python 语句/第三方库,可以选择不使用 numba 来规避。这是我选择 Numba 的原因。

    首先:应该编译(优化)什么?

    由于 Numba 本身的限制(稍后介绍),不能做到对整个程序完全的优化。实际上,也没必要这样做——只需要优化真正耗时间的部分即可。

    怎么找到真正耗时间的部分?除了靠直觉,还可以借用工具来分析,例如 Python 自带的 cProfile,还有 line_profiler 等,这里不再细讲。

    安装

    可以通过 conda 或 pip,一个命令安装:
    conda / pip install numba

    什么样的代码能加速?

    按照官方文档的示例代码,如果代码中含有很多数学运算、使用 NumPy,或者有不少 Python 的 for 循环(Python 性能大忌),那么 Numba 就能给你很好的效果。尤其是多重 for 循环,可以获得极大的加速。

    例如,下面这段代码,就能享受到 JIT:

    from numba import jit
    import numpy as np
    
    x = np.arange(100).reshape(10, 10)
    
    @jit(nopython=True)  # 设置为"nopython"模式 有更好的性能
    def go_fast(a):  # 第一次调用时会编译
        trace = 0
        for i in range(a.shape[0]):   # Numba likes loops
            trace += np.tanh(a[i, i]) # Numba likes NumPy functions
        return a + trace              # Numba likes NumPy broadcasting
    
    print(go_fast(x))

    但是,类似下面的代码,Numba 就没什么效果:

    from numba import jit
    import pandas as pd
    
    x = {'a': [1, 2, 3], 'b': [20, 30, 40]}
    
    @jit
    def use_pandas(a):  # 这个函数就加速不了
        df = pd.DataFrame.from_dict(a) # Numba 不支持 pd.DataFrame
        df += 1                        # Numba 也不支持这个
        return df.cov()                # 和这个
    
    print(use_pandas(x))

    总之,Numba 应付不了 pandas。以我的经验,需要把 DataFrame 转成 np.ndarray,再输入给 Numba。

    要强制用 nopython 模式

    刚才 work 的代码中,@jit(nopython=True) 这里传入了 nopython 这个参数,而不 work 的代码中,就没有这个参数。为什么呢?

    这是因为,@jit 实际上有两种模式,分为别 nopython 和 object 模式。只有 nopython 模式,才是能真正大幅加速的模式。而 nopython 模式只支持部分的 Python 和 NumPy 函数,如果运行时用到了不支持的函数/方法,程序就会崩掉 (例如刚才不能加速的例子) 。如果不强制设定 nopython 模式,编译函数失败时,会回退到 object 模式,程序虽然不会崩,但却偏离了我们给它加速的本意。

    我既然用了 Numba,我就希望它能真正地发挥作用。所以我选择强制开启 nopython ,如果不能加速,不如让它直接抛 exception。

    阅读更多…
  • 安利一个美股历史数据Python库:yfinance

    相比A股和港股,(免费的)美股的数据没有那么容易拿到,而适合Python的source/library就更少了。

    最近找到一个免费、轻量的Python库——yfinance。整个库只有几个文件,数据从yahoo下载,免费无限制。安装及使用教程见上面的链接。

    无需申请token,即装即用,和tushare一样方便,值得拥有。赶紧 pip install 一个吧。

    附上 github 上的一点使用文档:

    import yfinance as yf
    
    msft = yf.Ticker("MSFT")
    
    # get stock info
    msft.info
    
    # get historical market data
    hist = msft.history(period="max")
    
    # show actions (dividends, splits)
    msft.actions
    
    # show dividends
    msft.dividends
    
    # show splits
    msft.splits
    
    # show financials
    msft.financials
    msft.quarterly_financials