2020年5月

公司的生产环境里的服务器是禁止了绝大多数互联网连接的,但是有些环境又只有生产环境里有。为了方便,以前总是直接ssh进去用vim写代码,但是总觉得效率还是不够高。(这是我的问题😄)。另一个方法是在本地机器上写好代码,然后rsync过去一把梭。但是写一些稍大的工程的时候,一把梭很难成功。今天决定趁周末解决这种“非技术问题”。

远程搬砖码字调试的意思如下图: vscode-remote-dbg-arch

画个重点就是:

  • 本地机器上安装好VS Code;
  • 远程机器上安装好调试工具(vscode-server);
  • 代码留在远程机器上,本地机器仅作为"文本编辑器"这样的前端界面;

本地机器安装远程调试插件(Remote Development Extension)

这个步骤没什么难度,因为本地机器是可以连上网的。在VS Code的Extension页面搜索"Remote Development"安装便是。 这边提一句,笔者的环境是“墙中墙”,运行VS Code的也是一个“虚拟机”,里面也没网。像这样的情况,需要根据远程连接的类型(SSH, WSL, Docker...)选择具体的插件,比如SSH的话去 https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh 这个页面,点击右侧的"Download Extension"下载一个vsix后缀的文件传到墙里面。然后选择下图"..."里面的"Install from VSIX"离线安装

install_from_vsix.PNG

离线安装vscode-server调试服务器

正常安装完远程调试插件以后,左侧边栏会多出一个远程连接的tab. 创建一个连接以后,右键那个连接选择"connect to host using new window"会新建一个窗口连接远程服务器。右下角会弹出一个泡泡提示正在安装什么的,这时候要点击"details"看一下详情。这个步骤因为没有网络,它是永远无法完成的...除非我们人为帮他下载好了放好

install_vs_debug_server.PNG 留意上图红框中的commit hash,我们需要从微软官网手工把这个东西下载下来。

找个有网的机器,去下载https://update.code.visualstudio.com/commit:${commit_id}/server-linux-x64/stable,地址里面的${commit_id}用刚才红框里的代替。下载下来应该是个tar文件,然后把它传到你的远程机器上一个临时位置,这边存放的文件夹用/tmp代替. 随后操作:

  1. 创建vscode-server的文件夹
  2. 解压缩
  3. touch一个0文件,表示加载已经全部完成 具体bash如下:
    mkdir -p ~/.vscode-server/bin/${commit_id}
    # assume that you upload vscode-server-linux-x64.tar.gz to /tmp dir
    tar zxvf /tmp/vscode-server-linux-x64.tar.gz -C ~/.vscode-server/bin/${commit_id} --strip 1
    touch ~/.vscode-server/bin/${commit_id}/0

    搞定之后,重新执行刚才的连接远程服务器的操作。这时候如果去看details会发现VS Code认为服务器文件已经下载好了,于是他就会开始各种部署。

离线安装扩展插件到远程服务器

成功连接后你会发现一些本地装好的插件在远程是没有的。比如下图中的C++插件就是处于本地有但是远程没有的状态。这种插件一般都是需要获取编译运行环境的,由于本地无法模拟远程环境,所以必须要在远程装对应插件。

remote_ext_vscode.PNG

离线安装远程插件其实不难。将上文提到的VSIX离线文件下载了传到远程服务器上后(注意vsix有些是区分平台的,要和远程服务器平台一致,而非本地),可以直接安装。

序:老婆大人的XPS13突然坏了,体现在电源口歪斜、转轴部分螺丝松动。拆机后发现是C面的问题,具体从D面看是右上角螺丝的底座柱(类似螺母)碎裂了。无奈花了300块淘宝了一个C壳拆了老半天换上。装好之后一切看起来都很完美,但是插上原装电源开机后BIOS就报错了,提示类似下图: dell_ac_adapter_error.jpg(source: https://www.dell.com/community/Inspiron/AC-Power-Adapter-Alert-Inspiron-5558/td-p/6109628)

意思是电源适配器无法识别,电脑无法充电。这个时候选择Continue是可以进操作系统的,但是系统也会显示电源连接但是不在充电的状态。

一开始以为是适配器哪里崩了,后来一想这种原装电源挂掉概率实在是太小了,怀疑是电源适配器接口的故障。淘宝又花了十几块买了个电源头(型号00P7G3)换上,发现恢复了正常。拆下来的电源头仔细揣摩了一下,似乎是拧螺丝的时候把一根线压到了(但是没看见断),这个大概跟功率识别有关系吧!

dell_ac_power_socket.jpg

btw, 官网上找到了中文的拆机手册。发现比联想的黑白HMM写的好一点,顺道分享了~

xps-13-9360-laptop_service-manual_zh-cn.pdf 链接:https://pan.baidu.com/s/1Q8KYxEB-Vi6JyPvzFS659w 提取码:cxrk

后记:修好了之后,老婆大人并没有表示特别开心,反而说什么“键盘比以前难摁了”之类的。看来是想用新电脑了吧Orz.

It seems that Python writes to /tmp on linux base os when allocating python.multiprocessing.sharedctypes.RawArray. If the disk space on that path is not sufficient, "no disk space" error occurs. The solution is to change the default TMPDIR environment, using one of below methods:

  • bash: export TMPDIR='/the/new/path'
  • bash: TMPDIR=/the/new/path python3 your_script.py
  • python: os.environ['TMPDIR']='/your/new/path'

By the way, using /dev/shm as the tmpdir enhances performance to me~

iPadPro_0.jpg

生日的时候老婆大人送了一台iPad,相比之前使用的iPad Pro 2017 (10.5 inch)感觉提升还是挺大的。

首先的提升是屏幕,大了0.5英寸, 屏占比提升了不少。其实2017 iPad Pro还有个奇怪的CPU过热问题:CPU发热量比较大,然后屏幕在CPU附近的区域会被“烤”黄。这个现象在白色显示的时候比较明显。不知道为什么,觉得屏幕素质还是比先辈提升了一点点。

iPadPro_2.jpg

CPU和内存方面有了显著提升,但是对我而言上手实际感觉出来不了多少。A10X变成了A12Z,内存从4GB提升到了6GB。但是库克还是比较省材料啊,想来安卓的手机内存都有8GB了。

ipad_pro_4.png

重量上面,这两台机器其实是很相似的。10.5寸款是477 g,新款轻了6g。如果不戴套的话,手持感觉相当棒~一般来说如果我看Kindle的话就会把套子去掉。推荐买那种背面磁吸的手机壳,拆装很方便!

iPadPro_case.jpg

本次更新最大的提升点是摄像头,但是鄙人用iPad摄像头的机会是少之又少。稍许试了一下,相比17款,摄像头的拍摄效果有巨大提升,特别是景深传感器感觉是下一代iPhone的提前布局。

总而言之,如果手持是10.5寸Pad设备的话,强烈建议换机。但如果用的2018款的iPad Pro,除非要用到摄像头,否则不建议再花钱啦~

C++11有了一些关于线程的模型,在此之前C++里可是各自为政的,各种线程库各种神奇用法。其中有两个好玩的东西就是std::promise<T>std::future<T>,下文书中形容它们像是个“虫洞”。

  • std::future是虫洞的出口:一个未来对象的“获取器”,在未来的某一刻它能返回一个有用的值,但现在还没有...
  • std::promise是虫洞的入口:我们要保证在未来的某一刻给一个值进去,但不是现在...

Basic usage

一般来说这俩是成对使用的,看个代码:

#include <cassert>
#include <chrono>
#include <future>
#include <iostream>
#include <string>
#include <thread>

using namespace std::chrono_literals;

int main()
{
  std::promise<int> p1, p2;
  std::future<int> f1 = p1.get_future();
  std::future<int> f2 = p2.get_future();

  p1.set_value(42);
  assert(f1.get() == 42);

  std::thread t([&]() {
    std::this_thread::sleep_for(100ms);
    p2.set_value(43);
  });

  auto start_time = std::chrono::system_clock::now();
  assert(f2.get() == 43);
  std::chrono::duration<double, std::milli> elapsed = std::chrono::system_clock::now() - start_time;
  std::cout << "Waited " << elapsed.count() << " ms\n";
  t.join();
  return 0;
}

// output: Waited 100.253 ms                                                                                                                                                       

一个future对象可以通过promise.get_future()方法创建出来。当我们有真正的值来填进promose对象的时候,就用promise.set_value(v)方法。同时,(一般是在另一个线程里)当准备要获取值的时候,就调用future.get()方法。get方法会保持阻塞状态直到一个有效值被填进去。

值得一提的是,有一个特化的T = void。这货有啥用呢?可以用来阻塞等待某个并行任务完成:

std::promise<void> ready_p;
std::future<void> read_f = ready_p.get_future();

std::thread thread_b([&]() {
    prep_work();
    ready_p.set_value(); // no arg
    main_work();
});
ready_f.wait();
// now that thread B has completed

A bit of details

需要留意的是,promise也好future也罢,都是有动态内存分配(dynamic memory allocation)的开销的。 std_promise_future_schema.PNG(图源为参考文献)

留意图中的那个State对象,它基本上是一个shared_ptr——因为虫洞的两端(很可能是不同线程)都要用到这个共享对象(shared ownership)。所以创建std::promose/std::future的时候都是要申请新的堆空间。

Reference

本文全文参考自本书: <Mastering the C++17 STL: Make Full Use of the Standard Library Components in C++17>