veer66

veer66

(Posted on 2022-03-22)

  1. Lisp taught me to create functions that transform data step by step instead of adding mutable variables into loops. An immutable data structure is important for transforming data step by step without messing up existing data. Lisp's default data structure is a singly linked list.

  2. Lisp macro is easy to write compared to competitors. Rust's macro is powerful. Rust's macro is about transforming a TokenStream, and #Lisp's macro is about transforming a list. However, I prefer transforming a list to a TokenStream since I don't have to learn new structures and new commands for manipulating a new structure.

(Posted on 2022-03-22)

I translated my function in Lisp to Python.

def get_the_longest_prefix(a, b, ans):
    if len(a) == 0 or len(b) == 0:
        return "".join(ans)
    if a[0] == b[0]:
        return get_the_longest_prefix(a[1:], b[1:], ans + [a[0]])
    if a[0] == '-':
        return get_the_longest_prefix(a[1:], b, ans + ['-'])
    if b[0] == '-':
        return get_the_longest_prefix(a, b[1:], ans + ['-'])
    return "".join(ans)

And it has too many “return” statements. Anyway, I suppose Python doesn’t prefer a recursion. So this isn’t the case when we code in the Python way.

The code above concatenate Python's lists instead of creating a linked list like in Lisp.

So I made this experiment.

import time

n = 100

# Concatinating vectors
v = []
t1 = time.time_ns()
for i in range(n):
    v = [i] + v
t2 = time.time_ns()

# Creating cons cells for a singly link list
l = None
t3 = time.time_ns()
for i in range(n):
    l = (i, l) # Creating a cons cell
t4 = time.time_ns()

print((t2-t1)/(t4-t3))

At n = 100, concatenating vectors require 2 times of running time compared to creating cons cells for a linked list. So I keep using linked lists.

(Posted on 2022-03-14)

I want to install a specific version of RocksDB across different machines with different operating systems. Thus I can't rely on APT or other package management systems. I followed INSTALL.md by running make on the bundled Makefile, but last Saturday, I found that RocksDB couldn't read Snappy compressed data, although I installed the “libsnappy-dev” package. I tried many different ways to enable Snappy support. Then I decided to use CMake, which appeared only once in INSTALL.md. Now it works. My install script looks like this:

#!/bin/bash 
wget https://github.com/facebook/rocksdb/archive/refs/tags/v6.15.5.tar.gz -O - \ 
   | gzip -d \ 
   | tar -xf - \ 
   && pushd rocksdb-6.15.5 \ 
   && cmake -DWITH_SNAPPY=YES -DCMAKE_INSTALL_PREFIX=$MTDIR . \ 
   && DEBUG_LEVEL=0 PREFIX=$MTDIR make -j $(nproc) \ 
   && DEBUG_LEVEL=0 PREFIX=$MTDIR make install \ 
   && popd

$MTDIR is a target directory for installing RocksDB. DEBUG_LEVEL=0 and PREFIX=$MTDIR are perhaps not necessary.

(Posted on 2022-02-14)

โปรแกรมตัดเกรดเป็นตัวอย่างของ business logic ที่ดีเลยครับ เพราะว่าหลายครั้งก็มีการเปลี่ยนแปลงกฎเกณฑ์ วิธีคิดเกรดของแต่ละสถาบันไม่เหมือนกันก็ได้ บางวิชาในสถาบันเดียวกันก็ตัดเกรดไม่เหมือนกัน บางมีชามี A B C D F บางวิชามีเกรดแค่ S กับ U

อย่างไรก็ตามวิธีคิดเกรดในประเทศไทยมันไม่ค่อยเปลี่ยนแปลงอาจจะไม่เห็นภาพ ถ้าจะปรับให้เหมาะกับบริบทประเทศไทยควรจะเปลี่ยนโจทย์เป็นการคำนวณว่าใครได้เป็นส.ส.และส.ว.บ้างเพราะว่ารัฐธรรมนูญและกฎหมายลูกเปลี่ยนบ่อยเหลือเกิน และยังมีประเด็นในการตีความด้วย

เพราะว่าโปรแกรมเปลี่ยนตามกฎเกณฑ์ต่าง ๆ ซึ่งบางทีก็เปลี่ยนสามเดือนหลังจากที่เขียน บางทีก็สามปี บางทีก็สิบปี คนที่มาแก้ไขก็อาจจะเป็นคนละคนกับที่เขียนทีแรก

ถ้าอยากให้โปรแกรมแก้ไม่ยาก ก็จำเป็นต้องเดาใจคนอื่น เดาใจตัวเอง ว่าเขียนแบบไหนแล้วจะกลับมาอ่านง่ายหลังจากผ่านไปหลายปี และเขียนแบบไหนถึงจะกลับมาแก้ง่ายหลังจากผ่านไปหลายปี เป็นต้น

เรื่องว่าโปรแกรมทำงานช้าเร็วใช้หน่วยความจำมากน้อยก็สำคัญ แต่ก็ต้องพิจารณาเป็นกรณีไป หลายกรณีที่โปรแกรมมีประสิทธิภาพพออยู่ก็ไม่จำเป็นต้องไปปรับแต่งอีก

(Posted on 2022-01-28)

I agree that using JavaScript increases the chance of participation. I released a few versions of Thai word breakers in different programming languages. One on node.js is the most popular. 8 people contributed to the JS-based project compared to 2-3 people in other programming languages. However, JS has a downside too. In 2017, @iporsut and I made an experiment to compare Thai word breakers that we created. JS version running time is 15X of the Rust version. Even by comparing with another dynamic language, the Julia version is faster than the one in JS.

I created a website using node.js in 2014, and it is still running. The performance is good. However, I have a few regrets.
* We had a very hard time by install this project on other team members who use Windows 10 because we didn't know how to build a Bcrypt library. * Recently, I have to fix the project without adding any new feature because Express.js was changed, MongoDB was changed, and some packages that I used were abandoned. * It was a small project so I wanted to keep the session storage in RAM, but I can't since I ran 4 node.js processes. Now the project requires Redis as session storage, which causes more troubles for team members, who don't familiar with GNU/Linux, Docker, or WSL.

โม้ว่าทำอะไรเกี่ยวกับ Rust บ้าง 2021

(Posted on 2021-12-01)

ทีแรกผมจะเขียนเตรียมไว้พูดในงาน Rustacean Bangkok 2.0.0 แต่ว่าวันงานไม่ว่าง ก็เลยเอามารวมเป็น blog ไว้ก่อนแล้วกัน

ผมจะเล่าว่าผมทำอะไรกับภาษา Rust บ้างซึ่งก็คงไม่ครบถ้วน จะเขียนไปตามที่นึกได้

2014

ผมเริ่มเขียน Rust ครั้งแรกค.ศ. 2014 อย่างน้อยก็ที่ใส่ gist ไว้ code

#[deriving(Encodable, Decodable, Show, Clone)]
pub struct Node {
    pub snode: ~[~[Range]],
    pub children: Option<~[Option<Node>]>,
}

เป็นช่วงก่อนที่จะออก Rust 1.0 หน้าตาก็ต่างจากเดี๋ยวนี้เยอะเหมือนกัน ส่วนมากเอามาทำงานที่เอาไว้เก็บ string-tree alignment แต่รายละเอียดเรื่องนี้ก็ข้ามไปดีกว่า

2015

ค.ศ. 2015 ผมนึกถึงโปรแกรมพื้นฐานที่ใช้บ่อย ๆ โปรแกรมตัดคำ ถ้าอยากให้ความถูกต้องสูงใช้ deepcut เลย ถ้าอยากให้ความถูกต้องสูงแต่เร็วขึ้นหน่อยใช้ attacut

แต่ถ้าเอาเร็ว libthai chamkho icu

chamkho ผมแบ่งขั้นตอนการตัดคำเป็น 3 ขั้น

  1. สร้าง directed acyclic graph (DAG) ของวิธีตัดคำที่เป็นไปได้ทั้งหมด
  2. หา shortest path บน DAG จากข้อ 1
  3. ถอด path จากข้อสองมาเป็นตำแหน่งของ string ที่ต้องตัด

ส่วนที่ปรับไปมาคือข้อ 1 ผมแยกแบบนี้

1.1 สร้าง edge จากคำในพจนานุกรมที่ตรงกับ sub-string 1.2 สร้าง edge 1.3 ตัด edge ที่ขัดกับกด cluster ซึ่งเป็น substring ที่ตัดไม่ได้ออก ข้อนี้เพิ่มมาในค.ศ. 2021

มีแค่นี้เลย เล่าย้อนกลับไปหน่อยว่าปลายค.ศ. 2002 ผมเริ่มทำโปรแกรมตัดคำออกมาเขียนด้วย C

เพราะผมลองใช้ NLTK ที่เขียนด้วย Python ทั้งตัวแล้วมันทำงานช้าเกิน

แต่ผมก็คิดว่าแอปก็ยังควรจะภาษาที่เขียนง่าย ๆ แบบ Python หรือ Ruby หรือ Lisp อยู่ดี

แต่ข้อจำกัดของตัวคำสมัยนั้นคือ

  1. หลายตัวเขียนด้วย C++ ผมเขียนไม่เป็นหลังจากเรียนอยู่นาน

  2. ไม่ค่อยเหมาะเอามา bind กับ Ruby และอื่น ๆ

  3. แก้ word list และกฎยาก

thaiwordseg ก็เลยใส่ word list ใน file กฎใช้ regex และ bind กับ Ruby มาให้เลย ดูโครงการได้ที่ sourceforge ยังมี package ของโครงการนี้อยู่บน SUSE Linux ด้วยครับ

ปลายค.ศ. 2015 ผมไปพูดเรื่อง Rust ใน Barcamp Bangkhen รอบนึง พูดประมาณในเอกสารนี้

2016

ค.ศ. 2016 พูดเรื่อง Rust ในกลุ่ม Mozilla ไทย มีหลงเหลือ slide อยู่บ้าง

ค.ศ. 2016 ตั้งกลุ่ม Facebook สำหรับชาว Rust ไทยขึ้นมา ถ้าจำไม่ผิดตั้งตามกลุ่ม Clojure ไทยเพราะเห็นว่ามีกลุ่มขึ้นมาก็ดี ทุกวันนี้กลุ่ม RustLangTH ก็ได้คุณ Nui Narongwet และคุณ Wasawat Somno ช่วยกันดูแลเป็นหลักเลย กราบขอบพระคุณครับ

2017

ค.ศ. 2017 ร่วมกับคุณ @iporsut ทดสอบ Rust ที่เอามาตัดคำโดยใช้ word list และยังไม่ได้ใช้ regex สรุปได้เลยว่าเอา Rust เร็วกว่า Go Java คือตัวที่เขียนด้วย Rust ใช้เวลาทำงานเพียง 60% ของ Go ยังไม่ต้องพูดถึงตัวอื่นที่ว่าช้ากว่านั้น

ส่วนพวก Python JavaScript Clojure คือช้ามาก ห่างกันเป็นเท่าตัว ดูรายละเอียดเพิ่มเติม

ค.ศ. 2017 พบปะชาว Rust ไทยไปอีกรอบนึง ตาม blog นี้

ค.ศ. 2017 ตั้งกลุ่ม Rust ไทยบน Telegram ทั้งกลุ่มใน Telegram ทั้ง Facebook ผมส่งมอบสิทธิ admin ไปหมดแล้ว สมมุติว่าตอนนี้ผมตายไปก็ไม่ผลกระทบแน่นอน

ค.ศ.2017 ผมแก้ bug บน servo พอมีบันทึกไว้ใน blog ของ servo ก็พบว่าเป็น bug ที่ผิดง่าย ๆ ใส่ตัวแปรสลับกัน

Rust จะประกาศ type ให้ต่างกันจน compiler ตรวจได้ว่าคนใส่สลับกันได้

แต่ก็แบบที่ให้เวลาใช้งานจริง ๆ ก็ไม่ได้ประกาศ type แบบที่ว่า i32 u32 เต็มไปหมด ใส่สลับกัน compiler ก็ตรวจไม่ได้อยู่ดี

ระหว่างผมเขียน Python กับ Rust รู้สึกว่าเขียน Rust ก็เกิด bug เยอะแยะอยู่ดี อาจจะว่าผมโง่ก็ได้ แต่มันเป็นตัวแปรควบคุมว่าผมก็โง่เหมือนเดิมเวลาเขียน Python หรือ Rust ก็ตาม 😛

2018

ค.ศ. 2018 ส่วนมากก็จะปรับปรุงโปรแกรมเก่า เริ่มเขียน HTTP server มาหุ้มตัวตัดคำบ้าง โดยใช้ Hyper ตอนนี้น่าจะรันไม่ได้แล้ว หน้าตาแบบข้างล่าง

impl Service for WordcutServer {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = WebFuture;

    
    fn call(&self, req: Request) -> Self::Future {
        match (req.method(), req.path()) {
            (&Post, "/wordseg") => wordseg_handler(req),
            (&Post, "/dag") => dag_handler(req),
            _ => not_found(req)
        }
    }
}

2019

ค.ศ.2019 ส่วนมากจะเป็น code พวก string-tree เหมือนห้าปีก่อน แต่ style ก็เปลี่ยนไปเยอะ หน้าตาประมาณข้างล่าง

quick_error! {
    #[derive(Debug)]
    pub enum TextunitLoadingError {
        CannotLoadToks(lang: LangKey, err: Box<Error>) { }
        CannotLoadLines(lang: LangKey, err: Box<Error>) { }
        CannotLoadLinks(err: Box<Error>) { }
        CannotAlignToks(lang: LangKey, line_no: usize, err: Box<Error>) { }
    }
}

#[derive(Debug)]
pub struct Textunit {
    pub bi_text: BiText,
    pub bi_rtoks: BiRToks,
    pub links: Vec<Link>,
}

2020

ค.ศ. 2020 ผม port extension สำหรับ full-text search ภาษาไทยบน PostgreSQL ของคุณ zdk (Di Warachet S.) มาเป็น Rust

ผมไม่ทราบว่าคุณ zdk คิดอย่างไร แต่ผมมองว่าการลงพวก ElasticSearch เพื่อที่จะใช้ full text search พื้น ๆ หรือแม้แต่เอามา query JSON document บนเว็บที่คนใช้พร้อมกันไม่ถึง 100% คน มันเพิ่มงาน กิน RAM กิน SSD ขึ้นอีกเยอะ ใช้ PostgreSQL แทนได้น่าจะดีกว่า ตัวที่เขียนด้วย Rust ผมตั้งชื่อให้ว่าชำฆ้อพีจี

ค.ศ. 2020 ผมเขียน JSON parser สำหรับ GNU Guile ชื่อ guile-json-parse ด้วย

2021

ค.ศ. 2021 ผมแก้ให้โปรแกรมตัดคำมี regular expression แบบ newmm และ nlpo3 แต่พบว่าทุกอย่างที่เคย optimize มาสูญสลายไปเกือบหมดเลย เพราะว่า regex แบบ fancy ใน Rust มันก็ไม่ได้เร็วกว่า regex engine ของ Python ที่เขียนด้วย C 😰

ถ้าจะคงความเร็วไว้อาจจะต้องเขียนกฎให้เป็นภาษา Rust เลยแบบที่ chamkho เคยทำมา หรือทำตาม libthai ที่มีกฎคล้าย ๆ newmm แต่เขียนด้วย C วิธีนี้เร็วแน่ แต่ว่าแก้ทีเหนื่อย จะเพิ่มภาษาใหม่หนักแรง

แต่ Rust มีทางออกที่สามคือใช้ regex-automata ของ Andrew Gallant ซึ่งตัวนี้ตามชื่อแปลง regex เป็น automata แบบที่ควรจะเป็น แต่ก็จะรับ regex แบบขยายของ newmm ไม่ได้ก็เลยต้องโม regex บ้าง

ทำให้เสร็จแล้ว newmm รันบน xeon ใช้เวลารัน 9.65 เท่าของ chamkho ผมว่าควรจะเขียนถึงเรื่อง profiling ด้วยแค่จะแยกไปอีกโพสต์

อีกภาษาที่หลัง ๆ ทำงานเร็วขึ้นมาก และสำหรับผมเขียนง่ายกว่า Rust เยอะมาก ๆ คือ Julia แต่ว่าก็ติดอยู่ 3 เรื่องคือ

  1. ไม่มี regex-automata บน Julia
  2. runtime ของ Julia เปิดช้า
  3. ทำ lib ลอกเลียนภาษา C ลำบาก ทำให้เอาไปใช้กับ cffi ใน Common Lisp หรือ Ruby ยาก

Common Lisp ก็เป็นอีกภาษาหนึ่งที่ optimize มาก ๆ แล้วก็เร็วสูสี Julia แต่ก็ติดประเด็นเดียวกันทั้งหมด

ทำให้ผมสรุปแบบนี้เลยว่า Rust นอกจากภาษาและ compiler แล้วยังเป็น community ที่ lib ดี ๆ ออกมาเยอะมาก หลายตัวหาในภาษาอื่นยาก

ค.ศ. 2021 อีกอย่างที่คือ เพื่อที่จะไป bind กับภาษาอื่นง่าย ๆ chamkho มี wrapper ทำให้กลายเป็น library ภาษา C แบบปลอม ๆ ชื่อ wordcutw

พอทำแบบนี้เวลาจะ bind กับ Ruby หรือภาษาอื่น ๆ ก็ไม่ต้องคิดอะไรใหม่เลยใช้ FFI ได้เลย ข้อดีของการใช้ FFI หรือ cffi คือมันจะไม่ยึดติดกับ implementation ตัวใดตัวหนึ่ง เช่น Common Lisp อาจจะใช้ implementation เป็น SBCL หรือ Clozure CL ก็ได้ แต่ถ้าใช้ cffi มา bind กับ wordcutw ก็จะใช้ได้ทั้ง SBCL และ Clozure CL โดยไม่ต้องแก้ code เลย

ค.ศ. 2021 ผมคิดว่าน่าจะไป chat กันแบบ protocol ที่เปิดและ decentralize บ้างก็เลยเปิด กลุ่ม Rust ไทยบน Matrix

ค.ศ. 2021 อีกอย่างที่ทำคือเทียบความเร็ว Apache Arrow กับ Pandas ผลคือถ้าเขียน Pandas ดี ๆ ก็เร็วได้ แต่ใช้ Arrow เร็วกว่า ยิ่งใช้ Rust ก็เร็วใหญ่ และไม่ต้องระวังเรื่องแปลงไปมาระหว่าง type ของ Rust และ Python ดูรายละเอียดเพิ่มเติม

ค.ศ. 2021 ก็มีเรื่องอื่น ๆ คือเขียน parser สำหรับ Apertium stream format โดยใช้ Nom ทำให้เขียน parser ง่ายขึ้นมาก; port โปรแกรม Attacut มาบน Rust ให้ชื่อว่า Khatson ปรากฎว่าไม่เร็วขึ้นเลยแต่ทำให้รู้ว่าใช้ tch ใน Rust ที่หุ้ม PyTorch ไว้ให้ เขียนพวก deep learning แบบเดี๋ยวกับใช้ PyTorch สะดวกมาก และสำหรับผมงงน้อยกว่าใช้ PyTorch ตรง ๆ

สถานการณ์ของ Rust ในไทย

สภานการณ์ปัจจุบัน ตอนนี้ผมคิดว่า Rust ติดลมบนไปแล้ว บริษัทขวัญใจมหาชนก็เป็นสมาชิก Rust Foundation ทั้ง AWS Facebook Google Huawei Microsoft Mozilla; celeb ก็เขียน Rust กันแล้ว สถานการณ์ในไทยก็ฝืนกระแสโลกไม่ไหวแน่ ๆ

ส่วนที่เป็นรูปธรรมมากคือคุณ Jojo จากช่อง KubeOps Skills ทำวิดีโอภาษาไทยขึ้นมาสอนเขียน Rust เลย ผมว่าอันนี้ดีมาก ๆ และตามที่เกริ่นไปคุณ Natechewin Suthison จะจัดงาน Rustacean Bangkok 2.0.0 วันที่ 13 ธันวาคม พ.ศ.2564 นี ทุกท่านกดดูรายละเอียดตาม link ไป Facebook ได้เลย

(Posted on 2021-11-15)

Install pre-requisited tools

sudo zypper install make gcc automake autoconf libtool aclocal wget
sudo zypper si -d emacs

Download Emacs source tarball

wget https://ftp.gnu.org/pub/gnu/emacs/emacs-27.2.tar.gz

Extract and change directory

tar xzvf emacs-27.2.tar.gz
cd emacs-27.2

Generate makefiles

./configure --prefix=/opt > log

Make

make -j `nproc`

Install

sudo make install

Add path

Add the line below to ~/.bashrc by nano ~/.bashrc

export PATH="/opt/bin:$PATH"

An incomplete WebSocket client based on only socket, ssl, and uuid in Python

A few days ago, I couldn't get a WebSocket library working with another library on Python 3.10. So to avoid those dependencies, I implemented my WebSocket client on a low-level socket API. I implemented one in Common Lisp first. Then I translated it to Python. My WebSocket client is very far away from being completed, but at least it can run.

The first part is import. I imported only three things that are socket, ssl, and uuid.

import socket
import ssl
import uuid

The second part is based on HTTP headers for telling the server to switch to the WebSocket mode.

def upgrade(s, conn_info):
    with s.makefile(mode = 'rw', encoding = "ISO-8859-1") as f:
        f.write(f'GET {conn_info["path"]} HTTP/1.1\r\n')
        f.write(f'Host: {conn_info["host"]}\r\n')
        f.write("Connection: Upgrade\r\n")
        f.write("Upgrade: websocket\r\n")
        f.write(f'Sec-Websocket-Key: {str(uuid.uuid1())}\r\n')
        f.write("Sec-WebSocket-Version: 13\r\n")
        f.write("\r\n")
        f.flush()
        
        # reading response
        for line in f:
            if line == "\n":
                break

The third part is reading a content length. I assume that the server keep sending text contents. In read_payload_len(), s.recv(1) read a byte from the socket s. & 0x7F is for masking only 7 bits. If length is 127, the length is in the next 4 bytes instead. If length is 126, the length is in the next 2 bytes. Otherwise the function just returns the length.

def read_payload_len(s):
    match s.recv(1)[0] & 0x7F:
        case 127:
            return read_extra_len(s, 4)
        case 126:
            return read_extra_len(s, 2)
        case l:
            return l

The read_extra_len reads bytes and turn them to integer.

def read_extra_len(s, num_of_bytes):
    buf = s.recv(num_of_bytes)
    len = 0
    for i in range(num_of_bytes):
        len += buf[i] << (8 * (num_of_bytes - i - 1))
    return len

In the fourth part, we read a web socket frame. The program determine a frame type from opcode, which in the last 4 bits of the header. I should implement PING-PONG part but I didn't. According to RFC6455, which I forgot to mention before, opcode == 0x1 means the frame is a text frame. So the program reads payload length and reads the payload.

def read_frame(s):
    header0 = s.recv(1)[0]
    opcode = header0 & 0x0F
    match opcode:
        case 0x1:
            payload_len = read_payload_len(s)
            print(s.recv(payload_len))
        case 0x9:
            print("PING")
        case 0xA:
            print("PONG")

The last part is for opening connections and SSL/TLS wrapper. The function created a socket and wrapped it with TLS/SSL wrapper. The sending upgrade message to ask the server to switch to Websocket mode and the keep reading frames.

def connect(conn_info):
    ctx = ssl.create_default_context()
    with socket.create_connection((conn_info["host"], conn_info["port"])) as s:
        with ctx.wrap_socket(s, server_hostname = conn_info["host"]) as ss:
            upgrade(ss, conn_info)
            while True:
                read_frame(ss)

In the final part, I cannot find any public Websocket endpoint besides ones from cryptocurrency exchanges. So I put Bitkub API.

connect({"host": "api.bitkub.com",
         "port": 443,
         "path": "/websocket-api/market.trade.thb_btc"})

And it works, but if you are unlucky, you will get PING instead.

> python3.10 http_ex.py 
b'{"amt":0.00004661,"bid":86911896,"rat":2140000,"sid":82187323,"stream":"market.trade.thb_btc","sym":"THB_BTC","ts":1636729677,"txn":"BTCSELL0011078574"}\n{"amt":0.23306074,"bid":86912246,"rat":2140000,"sid":82187325,"stream":"market.trade.thb_btc","sym":"THB_BTC","ts":1636729677,"txn":"BTCSELL0011078576"}'
b'{"amt":0.00466121,"bid":86912014,"rat":2140000,"sid":82187324,"stream":"market.trade.thb_btc","sym":"THB_BTC","ts":1636729677,"txn":"BTCSELL0011078575"}'

Download and unarchive

Download Python-3.10.0.tar.xz; tar xJvf Python-3.10.0.tar.xz; cd Python-3.10.0

Configure

I got this error message by running ./configure

./configure: line 10530: PKG_PROG_PKG_CONFIG: command not found

So I ran this:

docker run --rm --pull=always -v $(pwd):/src quay.io/tiran/cpython_autoconf:latest

Still configure cannot find g++, so I added CXX=c++ in front of configure.

So this was how I used configure:

CXX=c++ ./configure --enable-optimizations --prefix=/opt 2> elog > log

make

This step has no problem.

make -j8
sudo make install

Running python

pip3.10 and python3.10 cannot run since it can't find readline.

So I ran this.

ln -s /opt/lib64/python3.10/lib-dynload /opt/lib/python3.10/lib-dynload

Then python3.10 works now.

P.S. Thank every one who provide answers on issue trackers and forums. I should have kept URLs to those. Sorry that I didn't.

Actix has a supervisor that helps to restart an actor under its supervision. However, sometimes it doesn't. 😹

AFAIK something has to send a Die (message) to an actor when something went wrong. The actor has to implement a Die message handler. In the handler, it calls ctx.stop (context stop). When “Actor::stopping(...) == Running::Stop”, its poll function will return Poll::Ready. Then its supervisor can perform restarting.

In my case, all of these didn't work because of two reasons.

  1. Actor didn't stop properly. It stopped without calling the stopped function. So I suppose it has no chance to handle the Die message.

  2. Actor kept using the CPU when it went wrong. So the poll function was blocked. Then the actor cannot handle the Die message.

I fixed the first case by calling tokio::time::sleep, and the second case by breaking for the loop.

PS I'm not sure about what I wrote. Please tell me if I missed or misunderstood some things or even everything.