需要更多色彩的
不是代码,而是生活

轻松理解 Python 中的 async await 概念

旅行者1号阅读(302)

为了简化并更好地标识异步IO,从Python 3.5开始引入了新的语法async和await, 以下示例演示了如何使用这一新语法。

代码转自:https://blog.csdn.net/Likianta/article/details/90123678

from time import sleep, time


def demo1():
    """
    假设我们有三台洗衣机, 现在有三批衣服需要分别放到这三台洗衣机里面洗.
    """

    def washing1():
        sleep(3)  # 第一台洗衣机, 需要洗3秒才能洗完 (只是打个比方)
        print('washer1 finished')  # 洗完的时候, 洗衣机会响一下, 告诉我们洗完了

    def washing2():
        sleep(2)
        print('washer2 finished')

    def washing3():
        sleep(5)
        print('washer3 finished')

    washing1()
    washing2()
    washing3()

    """
    这个还是很容易理解的, 运行 demo1(), 那么需要10秒钟才能把全部衣服洗完.
    没错, 大部分时间都花在挨个地等洗衣机上了.
    """


def demo2():
    """
    现在我们想要避免无谓的等待, 为了提高效率, 我们将使用 async.
    washing1/2/3() 本是 "普通函数", 现在我们用 async 把它们升级为 "异步函数".

    注: 一个异步的函数, 有个更标准的称呼, 我们叫它 "协程" (coroutine).
    """

    async def washing1():
        sleep(3)
        print('washer1 finished')

    async def washing2():
        sleep(2)
        print('washer2 finished')

    async def washing3():
        sleep(5)
        print('washer3 finished')

    washing1()
    washing2()
    washing3()

    """
    从正常人的理解来看, 我们现在有了异步函数, 但是却忘了定义应该什么时候 "离开" 一台洗衣
    机, 去看看另一个... 这就会导致, 现在的情况是我们一边看着第一台洗衣机, 一边着急地想着
    "是不是该去开第二台洗衣机了呢?" 但又不敢去 (只是打个比方), 最终还是花了10秒的时间才
    把衣服洗完.

    PS: 其实 demo2() 是无法运行的, Python 会直接警告你:
        RuntimeWarning: coroutine 'demo2.<locals>.washing1' was never awaited
        RuntimeWarning: coroutine 'demo2.<locals>.washing2' was never awaited
        RuntimeWarning: coroutine 'demo2.<locals>.washing3' was never awaited
    """


def demo3():
    """
    现在我们吸取了上次的教训, 告诉自己洗衣服的过程是 "可等待的" (awaitable), 在它开始洗衣服
    的时候, 我们可以去弄别的机器.
    """

    async def washing1():
        await sleep(3)  # 注意这里加入了 await
        print('washer1 finished')

    async def washing2():
        await sleep(2)
        print('washer2 finished')

    async def washing3():
        await sleep(5)
        print('washer3 finished')

    washing1()
    washing2()
    washing3()

    """
    尝试运行一下, 我们会发现还是会报错 (报错内容和 demo2 一样). 这里我说一下原因, 以及在
    demo4 中会给出一个最终答案:
        1. 第一个问题是, await 后面必须跟一个 awaitable 类型或者具有 __await__ 属性的
        对象. 这个 awaitable, 并不是我们认为 sleep() 是 awaitable 就可以 await 了,
        常见的 awaitable 对象应该是:
            await asyncio.sleep(3)  # asyncio 库的 sleep() 机制与 time.sleep() 不
            # 同, 前者是 "假性睡眠", 后者是会导致线程阻塞的 "真性睡眠"
            await an_async_function()  # 一个异步的函数, 也是可等待的对象
        以下是不可等待的:
            await time.sleep(3)
            x = await 'hello'  # <class 'str'> doesn't define '__await__'
            x = await 3 + 2  # <class 'int'> dosen't define '__await__'
            x = await None  # ...
            x = await a_sync_function()  # 普通的函数, 是不可等待的

        2. 第二个问题是, 如果我们要执行异步函数, 不能用这样的调用方法:
            washing1()
            washing2()
            washing3()
        而应该用 asyncio 库中的事件循环机制来启动 (具体见 demo4 讲解).
    """


def demo4():
    """
    这是最终我们想要的实现.
    """
    import asyncio  # 引入 asyncio 库

    async def washing1():
        await asyncio.sleep(3)  # 使用 asyncio.sleep(), 它返回的是一个可等待的对象
        print('washer1 finished')

    async def washing2():
        await asyncio.sleep(2)
        print('washer2 finished')

    async def washing3():
        await asyncio.sleep(5)
        print('washer3 finished')

    """
    事件循环机制分为以下几步骤:
        1. 创建一个事件循环
        2. 将异步函数加入事件队列
        3. 执行事件队列, 直到最晚的一个事件被处理完毕后结束
        4. 最后建议用 close() 方法关闭事件循环, 以彻底清理 loop 对象防止误用
    """
    # 1. 创建一个事件循环
    loop = asyncio.get_event_loop()

    # 2. 将异步函数加入事件队列
    tasks = [
        washing1(),
        washing2(),
        washing3(),
    ]

    # 3. 执行事件队列, 直到最晚的一个事件被处理完毕后结束
    loop.run_until_complete(asyncio.wait(tasks))
    """
    PS: 如果不满意想要 "多洗几遍", 可以多写几句:
        loop.run_until_complete(asyncio.wait(tasks))
        loop.run_until_complete(asyncio.wait(tasks))
        loop.run_until_complete(asyncio.wait(tasks))
        ...
    """

    # 4. 如果不再使用 loop, 建议养成良好关闭的习惯
    # (有点类似于文件读写结束时的 close() 操作)
    loop.close()

    """
    最终的打印效果:
        washer2 finished
        washer1 finished
        washer3 finished
        elapsed time = 5.126561641693115
        	(毕竟切换线程也要有点耗时的)

    说句题外话, 我看有的博主的加入事件队列是这样写的:
        tasks = [
            loop.create_task(washing1()),
            loop.create_task(washing2()),
            loop.create_task(washing3()),
        ]
        运行的效果是一样的, 暂不清楚为什么他们这样做.
    """


if __name__ == '__main__':
    # 为验证是否真的缩短了时间, 我们计个时
    start = time()

    # demo1()  # 需花费10秒
    # demo2()  # 会报错: RuntimeWarning: coroutine ... was never awaited
    # demo3()  # 会报错: RuntimeWarning: coroutine ... was never awaited
    demo4()  # 需花费5秒多一点点

    end = time()
    print('elapsed time = ' + str(end - start))

Python调用ffmpeg视频转码实时获取进度的正确写法

旅行者1号阅读(678)

需求是这样的,就是Python调用ffmpeg转码,想要取到ffmpeg命令行实时输出的进度信息,以便做进一步的处理,然而就这样一个小小的需求弄了一天,原因是找遍了网上的例子,说的挺好,但一运行都不是我想要的结果,甚至去看了一个开源库ffmpy,它的实现方式也只能等待ffmpeg编码完成后才能返回信息,不是我要的结果。后来仔细翻阅文档,最终实现。主要是一定要设置bufsize,不然是不能实时的读取到的。

import subprocess as sp

FFMPEG_BIN = "ffmpeg"
input_file = 'input.avi'
output_file = 'output.mp4'

# 转码命令
cmd = [FFMPEG_BIN,
       '-y',
       '-i', input_file,
       '-acodec', 'aac',
       output_file]

# ffmpeg进度信息输出到标准错误流而不是标准输出流,这里将其错误流重定向到child管道中
# 重点是一定要设置bufsize=0,禁用缓冲区,否则信息不能及时输出
# universal_newlines=True将管道输出设为文本模式
child = sp.Popen(cmd, stderr=sp.PIPE, bufsize=0, universal_newlines=True, encoding='utf-8')

# child.poll()判断子进程是否结束
while child.poll() is None:
    line = child.stderr.readline().strip()
    if line:
        # 在此可以获取到ffmpeg每一次的信息输出
        print(line)

# ffmpeg进程结束,关闭流
child.stderr.close()

查看联通光猫EPON/4+1+WIFI(2.4G)自带路由器的admin密码,修改wifi密码

旅行者1号阅读(12839)

首先,在设备背面的标签上有一个user账号,但这个是个普通的账号,没有修改wifi密码等权限,而admin账号并没有在标签上写明,要想修改wifi密码就要先找到admin账号的密码。

先连上网络,网线或wifi都可以,然后再在浏览器地址栏里输入:http://192.168.1.1/backupsettings.conf,按下回车键后,将会把这个配置文件下载下来,这个配置文件就是光猫的配置文件,里面包含了管理员密码,我们下载完毕后,直接用记事本的方式将其打开,然后在里面搜索AdminPassword,找到后,位于<AdminPassword>和</AdminPassword>之间的部分就是管理员密码了,一般为CUAdmin+八位数字,比如CUAdmin12345678。
找到密码之后,就可以登陆管理员帐号,管理所有的配置了,包括修改wifi密码。

x265,x264,qaac通过ffmpeg管道编码命令

旅行者1号阅读(1401)

 

ffmpeg -y -i video.mp4 -pix_fmt yuv420p -f yuv4mpegpipe - | x265 -o video.265 --crf 28 --y4m -

x264:

ffmpeg -y -i video.mp4 -pix_fmt yuv420p -f yuv4mpegpipe - | x264 --demuxer y4m --crf 23 -o video.264 -

qaac:

ffmpeg -y -i audio.mp3 -vn -acodec pcm_s16le -ac 2 -f wav - | qaac64 -i -V 70 -q 2 -o audio.m4a -

Windows10下用msys2编译ffmpeg并集成libx264,libx265,libfdk_aac

旅行者1号阅读(2016)

之所以自己编译ffmpeg,是因为内置的aac编码器实在太渣,128k勉强能用,再低了就失真太严重了,而且不支持he-aac,所以必须采用fdkaac,自己编译集成fdkaac的ffmpeg。

一、准备编译环境

1.安装msys2,网址:http://www.msys2.org/ ,我要编译64位,所以下载64位版本。下载完后直接安装就可以了。

2.配置pacman中科大和清华的镜像源。不配置的话pacman不仅下载速度慢,甚至有些包直接下载不下来,中科大和清华可以二选一,或使用其它可用的镜像源也可以。

编辑 msys2安装位置/etc/pacman.d/mirrorlist.mingw32 ,在文件开头添加:

Server = https://mirrors.tuna.tsinghua.edu.cn/msys2/mingw/i686
Server = http://mirrors.ustc.edu.cn/msys2/mingw/i686/

添加后的文件内容如下:

##
## 32-bit Mingw-w64 repository mirrorlist
##

## Primary
## msys2.org
Server = https://mirrors.tuna.tsinghua.edu.cn/msys2/mingw/i686
Server = http://mirrors.ustc.edu.cn/msys2/mingw/i686/
Server = http://repo.msys2.org/mingw/i686/
Server = https://sourceforge.net/projects/msys2/files/REPOS/MINGW/i686/
Server = http://www2.futureware.at/~nickoe/msys2-mirror/mingw/i686/
Server = https://mirror.yandex.ru/mirrors/msys2/mingw/i686/

编辑 msys2安装位置/etc/pacman.d/mirrorlist.mingw64 ,在文件开头添加:

Server = https://mirrors.tuna.tsinghua.edu.cn/msys2/mingw/x86_64
Server = http://mirrors.ustc.edu.cn/msys2/mingw/x86_64/

添加后的文件内容如下:

##
## 64-bit Mingw-w64 repository mirrorlist
##

## Primary
## msys2.org
Server = https://mirrors.tuna.tsinghua.edu.cn/msys2/mingw/x86_64
Server = http://mirrors.ustc.edu.cn/msys2/mingw/x86_64/
Server = http://repo.msys2.org/mingw/x86_64/
Server = https://sourceforge.net/projects/msys2/files/REPOS/MINGW/x86_64/
Server = http://www2.futureware.at/~nickoe/msys2-mirror/mingw/x86_64/
Server = https://mirror.yandex.ru/mirrors/msys2/mingw/x86_64/

编辑 msys2安装位置/etc/pacman.d/mmirrorlist.msys ,在文件开头添加:

Server = https://mirrors.tuna.tsinghua.edu.cn/msys2/msys/$arch
Server = http://mirrors.ustc.edu.cn/msys2/msys/$arch/

添加后的文件内容如下:

##
## MSYS2 repository mirrorlist
##

## Primary
## msys2.org
Server = https://mirrors.tuna.tsinghua.edu.cn/msys2/msys/$arch
Server = http://mirrors.ustc.edu.cn/msys2/msys/$arch/
Server = http://repo.msys2.org/msys/$arch/
Server = https://sourceforge.net/projects/msys2/files/REPOS/MSYS2/$arch/
Server = http://www2.futureware.at/~nickoe/msys2-mirror/msys/$arch/
Server = https://mirror.yandex.ru/mirrors/msys2/msys/$arch/

3.更新系统核心和各种包

打开msys2,运行命令pacman -Syu,更新系统核心组件和各种包,如下图:

输入“Y”键开始更新。
注意: 更新时可能会遇到下图的警告,这时一定要点击右上角的“X”来关闭窗口。

点击“X”关闭窗口后出现一个弹窗,如下图,点击“OK”

上面的更新没有结束,需要继续更新。再次打开msys2.exe,再执行一次pacman -Syu

 

输入“Y”等待更新完成。

4.安装各种依赖

(1) 安装基本工具,命令:pacman -S base-devel(默认全部安装)

 

(2)安装编译工具,包括gcc,make等,命令:pacman -S mingw-w64-x86_64-toolchain(默认全部安装)

(3)安装汇编,cmake,SDL,命令:pacman -S yasm nasm mingw-w64-x86_64-cmake mingw-w64-x86_64-SDL2

(4)替换"msys2安装目录/mingw64/bin/cmake-gui.exe",编译x265的时候会用到,但是这个cmake-gui.exe会依赖qt的动态库,这里我们并没有安装qt,需要换成官方下载的cmake-gui.exe,这个不需要依赖qt动态库,网站 https://cmake.org/download/ ,下载相同版本的替换掉内置的这个即可。

至此,编译环境配置完成。

二、下载源代码

ffmpeg git clone https://github.com/FFmpeg/FFmpeg.git

x264 git clone https://github.com/mirror/x264.git

x265 git clone https://github.com/videolan/x265.git

fdkaac git clone https://github.com/mstorsjo/fdk-aac.git

代码目录如下所示

三、编译x264

1.配置。打开“mingw64.exe”,cd到x264源码目录,执行命令 ./configure --enable-static,默认是不会生成静态链接库的,加参数--enable-static来生成静态链接库。

2.编译。make -j4,我这机器有4个核心,所以加了-j4参数加快编译。

3.安装。make install

四、编译x265

1.修改x265默认安装位置。修改x265源码目录/build/msys/make-Makefiles.sh文件,将“cmake -G "MSYS Makefiles" ../../source && cmake-gui ../../source”改为“cmake -G "MSYS Makefiles" -DCMAKE_INSTALL_PREFIX=/usr/local ../../source && cmake-gui ../../source”

内容如下所示:

#!/bin/sh
# Run this from within an MSYS bash shell
cmake -G "MSYS Makefiles" -DCMAKE_INSTALL_PREFIX=/usr/local ../../source && cmake-gui ../../source

2.执行脚本‘./make-Makefiles.sh’,过一会弹出cmake配置界面,如下图:

依次点击“Configure”,"Generate",然后关闭,回到命令行窗口。

3.编译。make -j4

4.安装。make install

五、编译fdkaac

1.生成配置文件。cd到fdkaac源码目录,执行命令autogen.sh

2.配置。,执行命令 ./configure

3.编译。make -j4

4.安装。make install

六、编译ffmpeg

1.修改pkgconfig环境变量

执行命令export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig":$PKG_CONFIG_PATH

2.配置。cd到ffmpeg源码目录,./configure --enable-gpl --enable-nonfree --enable-libx264 --enable-libx265 --enable-libfdk-aac --extra-cflags=-I/usr/local/include --extra-ldflags="-L/usr/local/lib -static" --pkg-config-flags="--static"。

3.编译。make -j4。在ffmpeg源码目录下会生成ffmpeg.exe。可以编码一个视频文件测试一下编译结果。

IDEA 读取application.properties中文乱码问题

旅行者1号阅读(931)

File -> Settings -> Editor -> File Encodings

将Properties Files (*.properties)下的Default encoding for properties files设置为UTF-8,将Transparent native-to-ascii conversion前的勾选上。如图所示:

最后,一定要把application.properties文件内容清空,重新建立才行!!!我也不知道为什么,可能是哪个部分有缓存吧。。。

设置Win10子系统Ubuntu的root密码

旅行者1号阅读(676)

安装完Win10的Ubuntu后,发现不知道root密码,初始化的时候也不让建root用户,后来了解到,Ubuntu的默认root密码是随机的, 即每次开机都有一个新的root密码。我们可以在终端输入命令 sudo passwd
然后输入当前用户的密码,enter,终端会提示我们输入新的密码并确认, 此时的密码就是root新密码。修改成功后,输入命令 su,再输入新的密码就ok了。

VMware Workstation 与 Device/Credential Guard 不兼容问题的解决

旅行者1号阅读(933)

VMware Workstation打开虚拟机时提示“VMware Workstation 与 Device/Credential Guard 不兼容”,如下图

原因是hyper-v引起的。

1.控制面板—程序——打开或关闭Windows功能,取消勾选Hyper-V,确定禁用Hyper-V服务。

2.打开Windows PowerShell(管理员),运行命令:bcdedit /set hypervisorlaunchtype off

3.重启系统

Windows防火墙导致目标主机无法被ping通的解决方案

旅行者1号阅读(1282)

进入到“控制面板\系统和安全\Windows Defender 防火墙”,在左侧找到“高级设置”,点开之后,点击“入站规则”,找到以下内容“文件和打印机共享(回显请求)”,右键选择启用规则,即出现绿色的对勾。此时如果网络没有故障即可以ping通了。

Windows10安装mysql8.0绿色版详细教程

旅行者1号阅读(1446)

1.下载mysql。官方下载页面是https://dev.mysql.com/downloads/mysql/,找到最下面,如下图,点击红色方框中的按钮进入下载页面。

点击“No thanks, just start my download.”开始下载。

2.下载完成后,解压。我这里解压到C:\mysql-winx64,如下图

3.创建配置文件。在mysql目录下即C:\mysql-winx64创建一个my.ini文件,内容一般如下即可,其中,数据库文件目录即datadir=D:\MySql\data是用于存放mysql存储的数据的,可以根据自己需要进行修改,要确保这个目录是已经存在的,且内文件夹内没有任何文件。如果不写,默认会在mysql目录下生成一个data文件夹存放数据。

# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html
# *** DO NOT EDIT THIS FILE. It's a template which will be copied to the
# *** default location during install, and will be replaced if you
# *** upgrade to a newer version of MySQL.

# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M

# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin

# These are commonly set, remove the # and set as required.
# basedir = .....
# datadir = .....
# port = .....
# server_id = .....


# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M 

[client]
#mysql客户端端口
port=3306
#客户端默认文本编码使用utf-8
default-character-set=utf8
[mysqld]
#mysql服务端口
port=3306
#mysql服务默认文本编码使用utf-8
character_set_server=utf8
#mysql目录,即解压的目录
basedir=C:\mysql-winx64
#数据库文件目录
datadir=D:\MySql\data
#修改sql_mode,使用严格sql模式
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

[WinMySQLAdmin]
#mysqld位置
C:\mysql-winx64\bin\mysqld.exe

4.安装服务,以管理员身份运行命令提示符,进入到C:\mysql-winx64\bin,然后输入命令mysqld install,如果回显“Service successfully installed.”,则mysql服务安装成功。

5.初始化。继续执行命令mysqld --initialize --console,此时可能会稍微等待一会,如下图,红框中是生成的默认密码,保存下来。

6.启动mysql。在任务管理器的服务选项卡中,找到MySql,右键选择“开始”,启动MySql服务。

7.登录mysql。如果MySql服务正常启动了,此时便可以使用root用户和上面生成的密码登录mysql了。登录命令为“mysql -u root -p”,如下图。

8.修改root密码。执行sql

alter user 'root'@'localhost' identified by 'newpassword';

重新加载权限表,使密码修改立即生效。

flush privileges;

9.配置MySQL允许外部访问

use mysql;
update user set host = '%' where user ='root';

10.防火墙入站规则里添加3306端口。

11.如果用sqlyog等工具登录mysql时出现“plugin caching_sha2_password could not be loaded...”这样的问题,参见 http://www.codezd.com/experience/85.html