Change My World by Program

0%

距离上一次发文已经快半年了,趁这个特殊的日子,我想记录一下这几个月的流水帐,算是我恢复更新的一个开始。感谢对我不离不弃的各位。

这个夏天主要做的事情就是去区县买了一套小两室,作为老婆明年开始在老家县城工作的新家。大家都知道,区县的房子是最没有投资的,并且今年重庆的房价横盘已久,那我们为什么要在这个时间点买呢,还要买最贵的楼盘之一。老婆买房子有自己的原因,而我不阻止她买是考虑到她未来几年都得在这里工作,并且这期间大概率会经历怀孕生娃的过程,如果没有一个便利的购物条件,没有一个良好的小区环境,没有一个稳定温馨的住所,没有一个好闺蜜在同一小区,我是不忍心她一个人在那边的。看房和交易的过程可以说是相当艰辛的,连续两三个月基本上都是每一两周都得回老家一趟,花费了大量的时间,还好,最后在我们领证前几天,收到了放款通知。所以,截止到目前,我们俩的贷款本息已经超过一百万了。

阅读全文 »

基本概念

  • React是一个用于构建用户界面的Javascript库,是DOM的一个抽象层
  • React主要用于构建UI

状态管理

State

Props

阅读全文 »

这是我读的刘慈欣的第三部作品,但是是她早期的作品了,所以感觉有些表达功底没有《三体》的深厚。可以把它当作看作《三体》的前传来看,里面有一些重复的人物,但是真实年代和身份可能又有一些没有重复。

我认为这部作品可以作为一个量子物理科普入门的作品,特别适合对物理或者科幻感兴趣的初学者。这部作品中讲述的大量物理知识其实是有理有据的,甚至用科幻的方式解释了很多我们人类目前还没能解释的事情。看完可能给人一种恐怖的气氛,特别是最后照片里面的人,但我特别喜欢那量子玫瑰。

另外,这部作品是我第一次在微信读书上听完的一部作品,不过各个听书应用目前除了专人录入的作品外,其他的作品的朗读都是机器翻译,体验还是有待加强。

  • 美妙人生的关键在于你能迷上什么东西。
  • 夜晚的灯塔一直都在,只是灯亮的时候,你才看见它。
  • 有时候,人最不能容忍在别人身上看到自己的影子。
  • 我发现,当你渴望某样东西时,道德的约束是多么无力。

图片属性获取

获取图片大小

1
img.shape	# 返回一个元组(height, width, pixels)

图片常用操作

显示图片

1
2
3
4
# 如果不加后面那两行,可能显示的图片是纯黑色的,无法正常显示
cv2.imshow('窗口名',image)
cv2.waitKey(0)
cv2.destroyAllWindows()

伸缩/压缩图片

1
2
img = cv2.imrerad('input.png')
img2 = cv2.resize(img, (512, 512), interpolation=cv2.INTER_CUBIC)

裁剪图片

1
img2 = img[0:128, 0:512]	# 四个点都必须为整数

图片匹配/查找子图片出现位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 以下代码来自https://stackoverflow.com/questions/50579050/template-matching-with-multiple-objects-in-opencv-python/58514954#58514954
import cv2
import numpy as np
import time

image = cv2.imread('smiley.png', cv2.IMREAD_COLOR )
template = cv2.imread('template.png', cv2.IMREAD_COLOR)

h, w = template.shape[:2]
method = cv2.TM_CCOEFF_NORMED
res = cv2.matchTemplate(image, template, method)

min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result) # 其中max_loc就是子图片的左上角的横纵坐标位置

# 如果想匹配多个,可以用下面这种方法
threshold = 0.90 # 设定一个最小的匹配度,所有匹配都有一个匹配度,从高往低计算
max_val = 1
while max_val > threshold:
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

if max_val > threshold:
res[max_loc[1]-h//2:max_loc[1]+h//2+1, max_loc[0]-w//2:max_loc[0]+w//2+1] = 0
image = cv2.rectangle(image,(max_loc[0],max_loc[1]), (max_loc[0]+w+1, max_loc[1]+h+1), (0,0,0) )

cv2.imwrite('output.png', image) # 这里会把匹配到的地方都标上黑框标记

视频常用操作

获取视频帧率帧数

1
2
3
4
movie = cv2.VideoCapture('test.mp4')
movie.get(cv2.CAP_PROP_FRAME_COUNT) # 帧数
movie.get(cv2.CAP_PROP_FPS) # 帧率
movie.release()

逐帧遍历

1
2
3
4
5
while True:
ret, frame = movie.read()
if not ret:
break
cv2.imwrite('filename.png', frame) # 将该帧以图片的形式保存下来

跳转到指定帧

1
2
movie.set(cv2.CAP_PROP_POS_FRAMES, 233)
ret, frame = movie.read()

上周“被”上线了一个紧急项目,周五下班接到需求,周一开始思考解决方案,周三开发完成,周四走流程上线,也算是面向领导编程了。之前的项目里面由于是自运维,然后大多数又都赶时间,所以在处理定时任务上面基本都是自己在服务器上添加crontab,而不是让多个实例自己去处理定时任务的并发锁,之后Laravel 5.5开始自带并发锁,我们也打算尽快升级。但是这次项目是Python项目,无奈只能自己实现一下,以下这个方案实现起来非常简单且易于理解。这篇文章要解决的主要问题是:使用Redis锁处理并发问题,保证多进程仅有一个实例在运行,当运行中的实例down了后其它实例中的一个能顶上来,保证有且仅有一个实例在运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import redis
r = redis.Redis(...)

last_heart = 0 # 记录上一次得到的锁心跳
free_lock_try = 6 # 锁无心跳的最大次数

while not r.setnx('mylock', 1):
now_heart = r.get('mylock')
print(f"没获取到锁,now_heart={now_heart},last_heart={last_heart},free_lock_try={free_lock_try}")
if now_heart == last_heart:
free_lock_try = free_lock_try - 1
if free_lock_try == 0: # 锁已经1分钟没有心跳了
old_heart = r.getset('mylock', 1) # 将lock重置为1,并返回set之前的心跳值
if old_heart < now_heart:
time.sleep(10)
continue
else:
break # 成功获取到锁,退出循环
else:
free_lock_try = 6 # 锁有心跳,重置free_lock_try值
last_heart = now_heart
time.sleep(10)

def producer_exit():
"""程序正常退出时候自动清理锁"""
r.delete('mylock')
import atexit
atexit.register(producer_exit)

# 业务代码
while True:
r.incr('mylock') # 让锁心跳加一
...

我们来看看这段程序都解决了并发锁中的哪些问题

  1. 高并发下,多个进程无法同时获取到锁。这里使用的是redis.setnx,如果锁已经存在,其他进程是无法重置锁并获取到锁的。另外当多个进程同时发现有锁已经没有心跳了,使用的是redis.getset将心跳重置为1,都能set成功,但是get出来的值多个进程是不一样的,只有真正获取到锁的进程返回的是之前进程的心跳,而其他进程获取到的都是1。
  2. 有锁进程正常退出,可以使用atexit注册进程退出函数删除锁,这里也可以不要,不过下次启动得等新的进程等待几次心跳
  3. 有锁进程意外退出,退出后心跳不再增加,超过free_lock_try次数后,其他进程会重新设置并获取锁
  4. 所有进程全都意外退出,这个问题不是锁来关心的,可以使用supervisor进行守护进程。

由于之前用pyspark写出来的spark程序在运行一段时间后会突然卡住,导致任务堆积,最终内存溢出。所以最近又决定直接用spark原生的scala语言来重写程序,scala大体上和java语言的语法是兼容的。

基本变量

  • val用于声明常量,var用于声明变量
阅读全文 »

Django自带了强大的名为admin的后台管理功能,app名称为django.contrib.admin,它同时依赖了django.contrib.auth认证系统和django.contrib.sessions系统,当然,即使不用admin,后面两者都建议加上,不用重复造轮子。

  • 为了使用它,我们需要先使用migrate功能去创建相应的数据库表,直接执行python manage.py makemigrations && python manage.py migrate即可。运行程序后,直接访问http://127.0.0.1:8000/admin/就能访问admin了(一般admin的路由都是定义好了的,在urls.py中有url(r'^admin/', admin.site.urls),)

  • 我们需要先创建一个超级管理员python manage.py createsuperuser,按照提示输入用户名密码即可用来登录了

  • 如果要让字段非必填,需要在定义model字段的时候就加上blank=True参数

  • 修改超级管理员密码可以这样做:

    1
    2
    3
    4
    5
    # python manage.py shell
    from django.contrib.auth.models import User
    user =User.objects.get(username='admin')
    user.set_password('new_password')
    user.save()
阅读全文 »

PHP上最好的时间处理工具。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 以下都是获得一个时间对象
Carbon::now(); // 获取当前时间,2018-01-01 11:11:11
Carbon::today(); // 获取今天的开始时间,2018-01-01 00:00:00
Carbon::tomorrow(); // 获取明天的开始时间,2018-01-02 00:00:00
Carbon::yesterday();// 获取昨天的开始时间,2017-12-31 00:00:00

# 解析时间,这个功能可以说是非常强大了,需要特别注意的是如果parse的字符串内部有带时区,那么解析后的对象也是自带时区的,可能跟当前时区是不一样的
Carbon::parse('2018-01-01');
Carbon::parse('2018-01-01 12:00:00');
Carbon::parse('today');
Carbon::parse('2 days ago');
Carbon::parse('+3 weeks');
Carbon::parse('last friday');
Carbon::parse('Fri May 31 2019 06:50:14 GMT+0000 (UTC)')->toDateTimeString(); // 这个会得到2019-05-31 06:50:14,而不是东8区的时间
Carbon::createFromFormat('Y-m-d H', '1975-05-21 22')->toDateTimeString(); // 1975-05-21 22:00:00


# 时间计算
Carbon::now()->addDays(3);
Carbon::now()->subHours(20);
Carbon::now()->modify('-2 days');

# 获取指定格式输出
Carbon::now()->toDateTimeString();
Carbon::now()->subDays(5)->diffForHumans(); // 5天前
Carbon::now()->dayOfWeek // 获取今天是星期几,直接返回一个数字
Carbon::now()->format('m/y') // 指定输出格式: 12/2020

Django提供了非常方便的方法以供你自定义存储系统,只需要在项目的任意地方新建一个继承自django.core.files.sotrage.Storage的类即可。如果是使用七牛云,可以直接使用以下代码,当然首先要安装七牛的sdk: pip install qiniu:

阅读全文 »

最近公司有一个安全方面的业务,需要实时监控所有访客的情况。之前是定时去查询Elasticsearch的接口进行统计分析,但是这个时间间隔不好把握,并且Elasticsearch并不适合特别实时的查询操作。实时的分布式流计算引擎首推Spark,它与Hadoop等相比的优势在这里讲得比较清楚了。

  • RDD(Resilient Distributed Dataset弹性分布式数据集):这是spark的主要数据概念。有多种来源,容错机制,并且能缓存、并行计算。RDD在整个计算流程中会经过不同方式的变换,这种变换关系就是一个有向无环图。
  • 需要注意的是,所有的方法在定义执行之前都是异步的,所以不能简单地在下面的方法外部添加try...catch...进行异常捕获,最好是在传入的函数里面进行异常的捕获(如果是lambda,请确认lambda不会报错,否则如果lambda报错整个程序都会报错并终止允许)
  • Spark应用程序可以使用大多数主流语言编写,这里使用的是python,只pip install pyspark即可
  • Stage(调度阶段): 每个Job会根据RDD大小切分城多个Stage,每个Stage包含一个TaskSet
  • TaskSet(任务集): 一组关联的Task集合,不过是没有依赖的
  • Task(任务): RDD中的一个分区对应一个Task。
  • Narrow Dependency(窄依赖): 比较简单的一对一依赖和多对一依赖(如union)
  • Shuffle Dependency(宽依赖): 父RDD的分区被多个子RDD分区所使用,这时父RDD的数据会被再次分割发送给子RDD
  • Spark 内存分配: 分为这三块:
    • execution: 执行内存,基本的算子都是在这里面执行的,这块内存满了就写入磁盘。
    • storage: 用于存储broadcast, cache, persist
    • other: 程序预留给自己的内存,这个可以不用考虑
  • Duration
    • batchDuration: 批次时间
    • windowDuration: 窗口时间,要统计多长时间内的数据,必须是batchDuration的整数倍
    • slideDuration: 滑动时间,窗口多长时间滑动一次,必须是batchDuration的整数倍,一般是跟batchDuration时间相同
阅读全文 »