为什么 LINK 和 AMPL 是空气币

先来说说 LINK

截止现在,18年到20年,最高价20多,最多涨了100倍。Defi 和 oracle 八竿子碰巧能打到一点点,最近和大热的 Defi 走的很近,市值也一度到了第五名。
买的早那是真香,但是有两个硬伤:

Read on →

拉埋点数据SQL三分钟速成

1. 基本选取

我们现在有一个表 user_action,有如下数据:

1
2
3
4
SELECT
*
FROM user_action
;
app_id app_version device_id sys_ver event_name
21370000 8.15.2 x000001 13.3 btn1_touched
21370000 8.15.2 x000001 13.3 btn1_touched
21370000 8.15.2 x000001 13.3 btn1_touched
21370000 8.15.2 x000002 14.0 btn2_touched
21370000 8.15.2 x000003 14.0 btn1_touched
21370000 8.15.2 x000003 14.0 btn2_touched

app_id app_ver 表示 app 和其版本号
device_id 为设备id
sys_ver 为系统版本号
event_name 为具体的事件名

Read on →

macOS BigSur 适配指引

在 Apple Silicon 上做性能分析

  • 原生代码一般都会比转码性能更好
  • 小心使用 Intel 专有的代码优化(SSE, AVX)
    • 可能需要针对 Apple Silicon 的优化版本
  • 尽可能使用 Apple 提供的 AP (Accelerate framework)

Apple Silicon 的非对称 CPU 核心

  • Apple Silicon Mac 有两种类型的核心
    • 高性能核心(P Cores)
    • 节能核心(Cores)
    • 在高并发任务场景下,所有的核心可以同时开启

避免使用忙等和 spinlock

  • 忙等会占用性能核心,进而导致任务延迟
  • 推荐的阻塞同步原语
    • NSLock, os_unfair_lock, pthread mutexes
    • NSCondition, pthread 条件变量
  • 避免按照 CPU 的数量划分工作任务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Prefer blocking locks and condition variables
func performWorkUnderSpinlock () {
  os_unfair_lock_lock()
  performWork()
  os_unfair_lock_unlock()
}

func retrieveNextWorkTask() -> WorkTask {
  condition.lock()
  while !taskQueue.hasAnyWork {
      condition.wait()
  }
  let task = taskQueue.pop()
  condition.unlock()
  return task
}

在 Apple Silicon 上调试、测试和性能分析

  • 构建工作可以使用任何 Mac,但是运行 arm64 代码只能在 Apple Silicon Mac 上
  • 分别测试原生和 Rosetta 的运行方式
  • 注意 Intel 专有代码和忙等的实现
第一方
从源码编译
和你的 app 一起发布
第三方
预先编译好的二进制
和 app 一起或者单独发布
进程内
进程外 x
原生 app 只能加载原生插件
Rosetta 转码 ap 只能加载 x86_64 插件

通过 XPC 使用进程外插件

  • 每个插件一个进程或者每种架构一个进程
  • 更好的稳定性和安全性

为了插件使用 Rosetta

  • 用户可以强制一个通用 app 通过 Rosetta 启动
  • 通过 Info.pist 关键字可以禁用
  • 详见 macOS 移植文档

警惕多线程缺陷

  • Intel CPU 和 Apple Silicon 采用不同的内存排序模型
  • 正确的代码有相同的行为,有缺陷的代码(争条件,数据竟争)却各有各的表现
    • 一个数据竞争在 Intel CPU 上也许不显露,却有可能在 Apple Silicon 上导致崩溃
    • Rosetta 提供 Intel CPU 相同的内存排序
  • 使用 Thread Sanitizer 来发现和防止数据竞争问题

兼容性

  • 兼容的 app 自动可见
  • 可以在 App Store Connect 管理

硬件的区别

  • 鼠标和触控事件
  • 环境传感器的区别
    • 陀螺仪
    • 指南针
    • 雷达摄像头
    • GPS
  • 相机
    • 使用 AVCaptureDeviceDiscoverySession 自动兼容
  • 照片选取

Diff: /Manifest.lock: No Such File or Directory: PODS_ROOT Not Defined

WeexSDK 增加 pods 依赖的时候提示:

diff: /Manifest.lock: No such file or directory

查看 shell script:

1
diff "${PODS_PODFILE_DIR_PATH}/Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null

echo 发现 PODS_ROOT 为空,导致 diff 右值传递为 ‘/Manifest.lock’,所以文件找不到。

查看 Pods-WeexSDK.debug.xcconfig 中对 PODS_ROOT 有定义:

1
PODS_ROOT = ${SRCROOT}/Pods

而且 project Info -> Configuration 下面指定了正确的 xcconfig。怀疑 PODS_ROOT 被某优先级更高的设置覆盖为空了。

全局搜索 PODS_ROOT,发现 target -> Build Settings -> User Defined 中对 PODS_ROOT 设置了空值。删除后问题解决。

C++ 10分钟速成

IDE 选择

PC

MinGW
VSCode

macOS

CLion (花钱)
Xcode

文章例子编译环境:
方言: GNU++14[-std=gnu++14] Standard library:libc++ (LLVM C++ standard library with C++11 support)

1. 指针

声明

1
2
3
4
5
6
7
8
9
10
11
int main() {
    string food = "Pizza";
    string* ptr = &food;
    cout << food << "\n";
    cout << &food << "\n";
    cout << ptr << "\n";
    cout << &ptr << "\n";
    cout << sizeof(ptr) << "\n";
    cout << sizeof(food) << "\n";
  return 0;
}

执行结果

1
2
3
4
5
6
Pizza
0x7ffeefbff560
0x7ffeefbff560
0x7ffeefbff558
8
24

类型

1
2
food  std::__1::string    "Pizza"  
ptr   std::__1::string *  "Pizza" 0x00007ffeefbff560

内存 (macOS, big-endian)

1
2
3
4
5
6
7
0x7ffeefbff558          0x7ffeefbff560
⬇️                      ⬇️
60 F5 BF EF FE 7F 00 00 0A 50 69 7A 7A 61 00 00
`  õ  ¿  ï  þ  .  .  .     P  i  z  z  a  .  .

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
Read on →

Pytorch Walkthrough on macOS

Env

macOS 10.15 | python 3.8.2 | torch 1.4.0 | torchvision 0.5.0

Install via pip

macOS binary 安装不支持 CUDA,如果需要 CUDA 请翻阅官网 install via source 安装指引。

1
2
pip3 install torch
pip3 install torchvision

安装成功后发现报错:

1
2
3
4
5
6
7
8
>>> import torch
toTraceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/torch/__init__.py", line 97, in <module>
    from torch._C import *
ImportError: dlopen(/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/torch/_C.cpython-38-darwin.so, 9): Library not loaded: @rpath/libc++.1.dylib
  Referenced from: /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/torch/_C.cpython-38-darwin.so
  Reason: image not found

libc++.1.dylib/usr/lib 下,使用 install_name_tool 解决:

1
install_name_tool -add_rpath /usr/lib /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/torch/_C.cpython-38-darwin.so

Hands-on-ml-readle

下载数据集

from sklearn.datasets import fetch_openml

mnist = fetch_openml(‘mnist_784’, data_home=‘./’) # downloaded from www.openml.org print(mnist)

如果提示 SSL: CERTIFICATE_VERIFY_FAILED,需要先更新证书:

1
sudo /Applications/Python\ 3.7/Install\ Certificates.command

修复 _adjustContentOffsetIfNecessary 导致 Scroll View 闪动问题

方法一

继承 scroll view,override _adjustContentOffsetIfNecessary 到空方法。

方法二

swizz scroll view _adjustContentOffsetIfNecessary 到其 category 的一个空方法中。

方法三

对应 UIViewController 的 automaticallyAdjustsScrollViewInsets 设置为 NO。

Gitbook Install and Use

首先安装 Node.js

https://nodejs.org/en/download/

然后安装 Gitbook

1
sudo npm install -g gitbook-cli

再安装 Calibre

Gitbook 的电子书格式转换需要调用 Calibre 的命令行工具。

https://calibre-ebook.com

然后:

1
ln -s /Applications/calibre.app/Contents/MacOS/ebook-convert ~/bin

最后切换到书的 git 目录下

1
gitbook mobi ./ ./book-name.mobi

Over

单页面隐藏 Navigation Bar,同时保持右滑手势退出页面的终极方案

1. 隐藏 navigation bar

在需要隐藏 navigation bar 的 view controller 中:

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
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self hideNavBar];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    [self showNavBar];
}

- (void)hideNavBar
{
    if (self.navigationController.viewControllers.lastObject == self) //避免推出下一个隐藏bar bar的vc过场动画展示了nav bar
    {
        [self.navigationController setNavigationBarHidden:YES animated:YES];
    }
}

- (void)showNavBar
{
    if (self.navigationController.viewControllers.lastObject == self) //避免推出下一个隐藏bar bar的vc过场动画展示了nav bar
    {
        [self.navigationController setNavigationBarHidden:NO animated:YES];
    }
}
Read on →