【Rust】列挙型

### 定数値として扱う

enum Color {
    Red = 0x0000FF,
    Green = 0x00FF00,
    Blue = 0xFF0000,
}
fn main(){
    let color = Color::Red;
    println!("{}", color as usize);
}

### 特定の値を指定しない時

enum Color {
    Red,
    Green,
    Blue,
}
fn main(){
    let color = Color::Red as usize;
    println!("{}", color);
}

### 値を持つ列挙型

enum Color {
    RGB(u8, u8, u8),
    RGBA(u8, u8, u8, u8),
}
fn main(){
    let c = Color::RGB(0, 0, 255);
    let code = match c {
        Color::RGB(r, g, b) => b as u32 + ((g as u32) << 8) + ((r as u32) << 16),
        Color::RGBA(r, g, b, _) => b as u32 + ((g as u32) << 8) +  ((r as u32) << 16),   
    };
    println!("{}", code);
}

### 値を持つenumを比較

#[derive(Debug,PartialEq)]
enum Animal {
    Dog(String),
    Cat(String),
    Monkey(String),
}

fn main(){
    let taro1 = Animal::Dog(String::from("Taro"));
    let taro2 = Animal::Dog(String::from("Taro"));
    assert_eq!(taro1, taro2);

    let taro3 = Animal::Cat(String::from("Taro"));
    let taro4 = Animal::Dog(String::from("Taro"));
    assert_eq!(taro3, taro4);

    let taro5 = Animal::Monkey(String::from("Taro"));
    let taro6 = Animal::Monkey(String::from("Taro"));
    // println!(taro5 as usize, taro6 as usize);
}

値を持つ、持たないで扱いが異なるのね。。
列挙型と構造体は何となく似ているが、列挙型は名前を列挙していくだけなので、型指定はしない。

【Rust】構造体と共用体

### 構造体

struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p = Point { x: 100, y: 200};
    println!("{} {}", p.x, p.y);
}

### 共用体
共用体は同じメモリを使用する

union MyUnion {
    f1: u32,
    f2: u32,
}

fn main() {
    let u = MyUnion {f1: 123};
    unsafe {
        println!("{}", u.f1);
        println!("{}", u.f2);
    }
}

$ ./main
123
123

【Rust】Ubuntu24.04にRustをインストールする

### rustが入っていない状態
$ cargo –version
bash: cargo: command not found

### インストール
$ cd $home
$ sudo apt-get update
$ sudo apt-get install libssl-dev libudev-dev pkg-config zlib1g-dev llvm clang cmake make libprotobuf-dev protobuf-compiler
$ curl –proto ‘=https’ –tlsv1.2 -sSf https://sh.rustup.rs | sh
$ source $HOME/.cargo/env

### 最新バージョンの確認
$ rustup component add rustfmt
$ rustup update

### インストール確認
$ cargo –version
cargo 1.83.0 (5ffbef321 2024-10-29)
$ rustc –version
rustc 1.83.0 (90b35a623 2024-11-26)

【Python】非同期処理を理解する

### 非同期処理とは?
あるタスクが終了するのを待っている間、別のタスクを実行すること

$ pip3 install aiohttp

import datetime
import aiohttp
import asyncio

start = datetime.datetime.now()

def log(message):
    print(f'{(datetime.datetime.now() - start).seconds}秒経過', message)

async def fetch(session, url):
    """ 非同期にURLからデータを取得 """
    print(f"Fetching {url}")
    async with session.get(url) as response:
        return await response.text()

async def main():
    log("タスク開始")
    urls = [
        "http://google.com",
        "http://qiita.com",
        "https://www.python.org/",
        "https://www.mozilla.org/en-US/",
        "https://html.spec.whatwg.org/multipage/",
        "https://www.w3.org/TR/css/",
        "https://ecma-international.org/",
        "https://www.typescriptlang.org/",
        "https://www.oracle.com/jp/java/technologies/",
        "https://www.ruby-lang.org/ja/",
        "https://www.postgresql.org/",
        "https://www.mysql.com/jp/",
        "https://docs.djangoproject.com/ja/5.0/",
        "https://spring.pleiades.io/projects/spring-boot",
        "https://rubyonrails.org/"
        "https://firebase.google.com/?hl=ja",
        "https://go.dev/",
        "https://nodejs.org/en"
    ]

    async with aiohttp.ClientSession() as session:
        tasks = [fetch(session, url) for url in urls]

        print("Starting tasks...")

        print("Tasks are running in the background...")

        results = await asyncio.gather(*tasks)

        for result in results:
            print(result[:100])

    log("task finished")

if __name__ == "__main__":
    asyncio.run(main())

【Python】threadingによる並列処理(マルチスレッド)

threadingというライブラリを使用する
今いるスレッドを確認

import threading
import warnings
warnings.simplefilter('ignore')

print(threading.currentThread().getName())

$ python3 main.py
MainThread

### threading.Threadでmainとは別にスレッドを作成する

import threading
import time
import warnings
warnings.simplefilter('ignore')

def boil_udon():
    print(" ■ thread :", threading.currentThread().getName())

    print(' うどんを茹でます。')
    time.sleep(3)
    print(' うどんが茹で上がりました。')

if __name__ == "__main__":
    print(" ■ thread :", threading.currentThread().getName())

    print('うどんを作ります。')

    # スレッドを作成
    thread1 = threading.Thread(target=boil_udon)
    thread1.start()
    thread1.join()

    print('うどんの盛り付けをします。')
    print('うどんができました。')

$ python3 main.py
■ thread : MainThread
うどんを作ります。
■ thread : Thread-1 (boil_udon)
うどんを茹でます。
うどんが茹で上がりました。
うどんの盛り付けをします。
うどんができました。

### スレッドを更に追加する

import threading
import time
import warnings
warnings.simplefilter('ignore')

def boil_udon():
    print(" ■ thread :", threading.currentThread().getName())

    print(' うどんを茹でます。')
    time.sleep(3)
    print(' うどんが茹で上がりました。')

def make_tuyu():
    print(" ■ thread :", threading.currentThread().getName())

    print(' うどんの汁を作ります。')
    time.sleep(2)
    print(' うどんの汁ができました。')


if __name__ == "__main__":
    print(" ■ thread :", threading.currentThread().getName())

    print('うどんを作ります。')

    # スレッドを作成
    thread1 = threading.Thread(target=boil_udon)
    thread2 = threading.Thread(target=make_tuyu)

    thread1.start()
    thread2.start()

    thread1.join()
    thread2.join()

    print('うどんの盛り付けをします。')
    print('うどんができました。')

$ python3 main.py
■ thread : MainThread
うどんを作ります。
■ thread : Thread-1 (boil_udon)
うどんを茹でます。
■ thread : Thread-2 (make_tuyu)
うどんの汁を作ります。
うどんの汁ができました。
うどんが茹で上がりました。
うどんの盛り付けをします。
うどんができました。

threadが作られると、同時に処理されていることがわかる
ThreadPoolExecutorの場合は、単純に1つの処理を複数のスレッドで実行するが、threadingの場合は、プログラム内容を指定してスレッドを作成することができる

Pythonでマルチスレッドとマルチプロセス

### シングルスレッド

from concurrent.futures import ThreadPoolExecutor
import time
def func():
    time.sleep(1)
start = time.time()
for i in range(8):
    func()
print(time.time() - start)

$ python3 single.py
8.064586639404297

### マルチスレッド(同時に実行)

from concurrent.futures import ThreadPoolExecutor
import time
def func():
    time.sleep(1)
start = time.time()
with ThreadPoolExecutor(max_workers=4) as e:
    for i in range(8):
        e.submit(func)
print(time.time() - start)

$ python3 multithread.py
2.0498673915863037

### マルチプロセス(複数のプロセスで同時に処理)

from concurrent.futures import ProcessPoolExecutor
import time
def func():
    time.sleep(1)
start = time.time()
with ProcessPoolExecutor(max_workers=4) as e:
    for i in range(8):
        e.submit(func)
print(time.time() - start)

$ python3 multiprocess.py
2.1424620151519775

import os
import time
import datetime
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor

x1, x2, y1, y2 = -1.8, 1.8, -1.8, 1.8
c_real, c_imag = -0.62772, -0.42193

def calculate_z_serial_purepython(maxiter, zs, cs):
    output = [0] * len(zs)
    for i in range(len(zs)):
        n = 0
        z = zs[i]
        c = cs[i]
        if (i % 100) == 0:
            time.sleep(0.0001)
        while abs(z) < 2 and n < maxiter:
            z = z * z + c
            n += 1
        output[i] = n
    return output

def calc_pure_python(desired_width, max_iterations):
    x_step = (float(x2 - x1) / float(desired_width))
    y_step = (float(y1 - y2) / float(desired_width))
    x = []
    y = []
    ycoord = y2
    while ycoord > y1:
        y.append(ycoord)
        ycoord += y_step
    xcoord = x1
    while xcoord < x2:
        x.append(xcoord)
        xcoord += x_step

    zs = []
    cs = []
    for ycoord in y:
        for xcoord in x:
            zs.append(complex(xcoord, ycoord))
            cs.append(complex(c_real, c_imag))
    
    output = calculate_z_serial_purepython(max_iterations, zs, cs)

if __name__ == "__main__":

    max_workers = os.cpu_count()
    start = datetime.datetime.now()
    for i in range(16):
        calc_pure_python(desired_width=500, max_iterations=100)
    elapsed = datetime.datetime.now() - start
    print("SingleThread: {}ms".format(elapsed.seconds*1000 + elapsed.microseconds/1000))

    start = datetime.datetime.now()
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        for i in range(16):
            executor.submit(calc_pure_python, 500, 100)
    elapsed = datetime.datetime.now() - start
    print("MultiThread: {}ms".format(elapsed.seconds*1000 + elapsed.microseconds/1000))

    # マルチプロセスの場合
    start = datetime.datetime.now()
    with ProcessPoolExecutor(max_workers=max_workers) as executor:
        for i in range(16):
            executor.submit(calc_pure_python, 500, 100)
    elapsed = datetime.datetime.now() - start
    print("MultiProcess: {}ms".format(elapsed.seconds*1000 + elapsed.microseconds/1000))

$ python3 main.py
SingleThread: 17934.699ms
MultiThread: 11256.051ms
MultiProcess: 8493.925ms

os.cpu_count() でCPUのコアを取得できるんか…
処理に時間がかかる箇所をマルチプロセスで実装すれば良さそうではあるな…

マルチスレッドとマルチタスク

– マルチコアシステムは2つ以上のコアが搭載されたシングルプロセッサCPU。L2キャッシュやフロントサイドバスなどを共有。コストを大幅に削減

– マルチタスクは複数のタスクでCPUなどの処理リソースを共有する方式。マルチタスクは各計算タスクを素早く切り替えることで、同時に行われているように見せる機能

– マルチコアは、異なるタスクに対して、複数の計算エンジンが独立して動作する。プロセスを別々のCPUコア間で分割することで、複数のアプリケーションを効率的に実行できる

– マルチスレッド処理: マルチタスク処理の理論をアプリケーションに適用したもので、1つのアプリケーション内のSiriを個々のスレッドに分割し、各スレッドは並列に実行される

マルチタスク処理

task.c

#include "kernel.h"
#include "kernel_id.h"
#include "ecrobot_interface.h"

#define COUNT 500 /* カウント数を500に定義 */

DeclareTask(Task1);
DeclareTask(Task2);

void ecrobot_device_initialize(){}

void ecrobot_device_terminate(){}

void user_1ms_isr_type2(void){}

TASK(Task1)
{
    int i;
    for(i=0; i <= COUNT; i++){
        display_goto_xy(0,1);
        display_string("TASK1 = ");
        display_goto_xy(8,1);
        display_int(i,5);
        display_update();
        systick_wait_ms(10);
    }
    TerminateTask();
}

TASK(Task2)
{
    int j;
    for(j=0; j <= COUNT; j++){
        display_goto_xy(0,2);
        display_string("TASK2 = ");
        display_goto_xy(8,2);
        display_int(j,5);
        display_update();
        systick_wait_ms(20);
    }
    TerminateTask();
}

tasks.oil

#include "implementation.oil"

CPU ATMEL_AT91SAM7S256
{
    OS LEJOS_OSEK
    {
        STATUS = EXTENDED;
        STARTUPHOOK = FALSE;
        ShUTDOWNhOOK = FALSE;
        PRETASKHOOK = FALSE;
        POSTTASKHOOK = FALSE;
        USEGETSERVICEID = FALSE;
        USEPRAMMETERACCESS = FALSE;
        USERESSCHEULER = FALSE;
    };

    APPMODE appmode1{};

    TASK Task1
    {
        AUTOSTART = TRuE { APPMODE = appmode1; }
        PRIORUTY = 1;
        ACTIVATION = 1;
        SCHEDULE = FULL;
        STACKSIZE = 512;
    };

    TASK Task2
    {
        AUTOSTART = TRuE { APPMODE = appmode1; }
        PRIORUTY = 2;
        ACTIVATION = 1;
        SCHEDULE = FULL;
        STACKSIZE = 512;
    };
};
#include "kernel.h"
#include "kernel_id.h"
#include "ecrobot_interface.h"

#define COUNT 500 /* カウント数を500に定義 */

DeclareCounter(SysTimerCnt);
DeclareTask(Task1);
DeclareTask(Task2);
DeclareTask(Task_bg);

void ecrobot_device_initialize(){}

void ecrobot_device_terminate(){}

void user_1ms_isr_type2(void){
    SignalCounter(SysTimerCnt); /* カウンタをIncrementする */
}

TASK(Task1)
{
    static int i=0;
    if(i <= COUNT){
        display_goto_xy(0,1);
        display_string("TASK1 = ");
        display_goto_xy(8,1);
        display_int(i,5);
        display_update();
        i++;
    } else {
        display_goto_xy(0,4);
        display_string("TASK1 Terminated");
        display_update();
    }
    TerminateTask(); /* 処理終了 */
}

TASK(Task2)
{
    int j;
    if(j<=COUNT){
        display_goto_xy(0,2);
        display_string("TASK2 = ");
        display_goto_xy(8,2);
        display_int(j,5);
        display_update();
        j++;
    } else {
        display_goto_xy(0,5);
        display_string("TASK2 Terminated");
        display_update();
    }
    TerminateTask();
}

task_bg.c

#include "kernel.h"
#include "kernel_id.h"
#include "ecrobot_itnerface.h"

#define TEMPO 10
#define VOLUME 50

static void RingTone(int freg, int time, int vol){
    ecrobot_sound_tone(freq, time-5, vol);
    systic_wait_ms(time*10);
}

TASK(task_bg)
{
    while(1){
/*===========かえるの歌=============*/
		RingTone(523, TEMPO*2, VOLUME);
		RingTone(587, TEMPO*2, VOLUME);
		RingTone(659, TEMPO*2, VOLUME);
		RingTone(698, TEMPO*2, VOLUME);
		RingTone(659, TEMPO*2, VOLUME);
		RingTone(587, TEMPO*2, VOLUME);
		RingTone(523, TEMPO*3, VOLUME);
		systick_wait_ms(TEMPO*10);

		RingTone(659, TEMPO*2, VOLUME);
		RingTone(698, TEMPO*2, VOLUME);
		RingTone(784, TEMPO*2, VOLUME);
		RingTone(880, TEMPO*2, VOLUME);
		RingTone(784, TEMPO*2, VOLUME);
		RingTone(698, TEMPO*2, VOLUME);
		RingTone(659, TEMPO*3, VOLUME);
		systick_wait_ms(TEMPO*10);

		RingTone(523, TEMPO*2, VOLUME);
		systick_wait_ms(TEMPO*2*10);
		RingTone(523, TEMPO*2, VOLUME);
		systick_wait_ms(TEMPO*2*10);
		RingTone(523, TEMPO*2, VOLUME);
		systick_wait_ms(TEMPO*2*10);
		RingTone(523, TEMPO*2, VOLUME);
		systick_wait_ms(TEMPO*2*10);

		RingTone(523, TEMPO, VOLUME);
		RingTone(523, TEMPO, VOLUME);
		RingTone(587, TEMPO, VOLUME);
		RingTone(587, TEMPO, VOLUME);
		RingTone(659, TEMPO, VOLUME);
		RingTone(659, TEMPO, VOLUME);
		RingTone(698, TEMPO, VOLUME);
		RingTone(698, TEMPO, VOLUME);
		RingTone(659, TEMPO, VOLUME);
		systick_wait_ms(TEMPO*10);
		RingTone(587, TEMPO, VOLUME);
		systick_wait_ms(TEMPO*10);
		RingTone(523, TEMPO*3, VOLUME);
		systick_wait_ms(TEMPO*10);
/*==================================*/
	}

    display_goto_xy(0,6);
    display_string("TASKbgTerminated");
    display_update();

    TerminateTask();
}

task_cycle.oil

#include "implementation.oil"

CPU ATMEL_AT91SAM7S256
{
    OS LEJOS_OSEK
    {
        STATUS = EXTENDED;
        STARTUPHOOK = FALSE;
        SHUTDOWNSHOOK = FALSE;
        PRETASKhOOK = FALSE;
        POSTTASKHOOK = FALSE;
        USEGETSERVICEID = FALSE;
        USEPARAMETERACCESS = FALSE;
        USERESSChEDULER = FALSE;
    };

    APPMODE appmode1{};

    TASK Task1
    {
        AUTOSTART = FALSE;
        PRIORITY = 2;
        ACTIVATION = 1;
        SCHEDULE = FULL;
        STACKSIZE = 512;
    };

    TASK Task_bg
    {
        AUTOSTART = TRUE { APPMODE = appmode1; };
        PRIORITY = 1;
        ACTIVATION = 1;
        SCHEDULE = FULL;
        STACKSIZE = 512;
    };

    COUNTER SysTimerCnt
    {
        MINCYCLE = 1;
        MAXALLOWEDVALUE = 10000;
        TICKSPERBASE = 1; // One tick is equal to 1msec
    }

    ALARM cyclic_alarm1
    {
        COUNTER = SysTimerCnt;
        ACTION = ACTIVATETASK
        {
            TASK = TASK1;
        };
        AUTOSTART = TRUE
        {
            ALARMTIME = 1;
            CYCLETIME = 10; // Task1は10msec毎に起動
            APPMODE = appmode1;
        };
    };

    ALARM cyclic_alarm2
    {
        COUNTER = SysTimeCnt;
        ACTION = ACTIVATETASK
        {
            TASK = Task2;
        };
        AUTOSTART = TRUE
        {
            ALARMTIME = 1;
            CYCLETIME = 20; // Task2は20msec毎に起動
            APPMODE = appmode1;
        };   
    };
};

一緒に実行させる命令文がいまいちよくわからんね。。。

【CPU】Task Status Segment

レジスタの状態をメモリに書き込む

struct TSS32 {
	int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3;  // タスクの設定
	int eip, eflags, eax, ecx, ebx, esp, ebp, esi, edi;  // 32bitレジスタ eipは拡張命令ポインタ 
	int es, cs, ss, ds, fs, gs;                          // 16bitレジスタ 
	int ldtr, iomap;
}

【Python】Proof of Stake

import hashlib
import json
from datetime import datetime
import random

class Block:
    def __init__(self, index, previous_hash, timestamp, data, validator):
        self.index = index
        self.previous_hash = previous_hash
        self.timestamp = timestamp
        self.data = data
        self.validator = validator
        self.hash = self.calculate_hash()

    def calculate_hash(self):
        block_dict = self.__dict__
        if 'hash' in block_dict:
            del block_dict['hash']
        block_string = json.dumps(block_dict, sort_keys=True).encode()
        return hashlib.sha256(block_string).hexdigest()

class Blockchain:
    def __init__(self):
        self.chain = []              # A list that holde the blocks of the blockchain
        self.unconfirmed_data = []   # A list of new data or transactions
        self.validators = {}         # A dictionary where each validator is recoded
        self.staked_tokens = {}      # A dictionary that holds the amount of staked tokens for each validator.
        self.minimum_stake = 500     # The minimum amout of tokens a validator must stake to participate in the network
        self.create_genesis_block()  # The genesis block is the first block in the blockchain.

    def create_genesis_block(self):
        genesis_block = Block(0, None, str(datetime.now()), "Genesis Block", None)
        self.chain.append(genesis_block)    
    
    def last_block(self):
        return self.chain[-1]

    def add_data(self, new_data):
        self.unconfirmed_data.append(new_data)

    def add_validator(self, validator, stake):
        if stake >= self.minimum_stake:
            self.staked_tokens[validator] = stake
            self.validators[validator] = True
        else: 
            print(f"{validator} does not meet the minimum stake requirement.")
    
    def select_validator(self):
        total_stake = sum(self.staked_tokens.values())
        selected_validator = None
        while selected_validator == None:
            pick = random.uniform(0, total_stake)
            print(pick)
            current = 0
            for validator, stake in self.staked_tokens.items():
                print(validator, stake)
                current += stake
                if current > pick:
                    selected_validator = validator
                    break
        return selected_validator

    def create_block(self, validator):
        if not self.unconfirmed_data:
            return False
        
        last_block = self.last_block()
        new_block = Block(index=last_block.index + 1,
                        previous_hash=last_block.hash,
                        timestamp=str(datetime.now()),
                        data=self.unconfirmed_data,
                        validator=validator)
        self.chain.append(new_block)
        self.unconfirmed_data = []
        return new_block.index

    def display_chain(self):
        for block in self.chain:
            print(f"Block {block.__dict__}")


# sample
blockchain = Blockchain()

blockchain.add_validator("A", 2000)
blockchain.add_validator("B", 50)
blockchain.add_validator("C", 650)
blockchain.add_validator("D", 30)
blockchain.add_validator("E", 100000)
blockchain.add_validator("F", 25)

blockchain.add_data("Alice send Bob 200 coin")
blockchain.add_data("Bob send Chen 2000 coin")

selected_validator = blockchain.select_validator()
print(f"Validator selected: {selected_validator}")

blockchain.create_block(selected_validator)
blockchain.display_chain()

$ python3 main.py
B does not meet the minimum stake requirement.
D does not meet the minimum stake requirement.
F does not meet the minimum stake requirement.
27576.935798973213
A 2000
C 650
E 100000
Validator selected: E
Block {‘index’: 0, ‘previous_hash’: None, ‘timestamp’: ‘2024-11-27 03:59:33.053116’, ‘data’: ‘Genesis Block’, ‘validator’: None, ‘hash’: ‘df536d1db7e82ccd6f51e244928263163cd36b9724c4fdb8df77a72923dca021’}
Block {‘index’: 1, ‘previous_hash’: ‘df536d1db7e82ccd6f51e244928263163cd36b9724c4fdb8df77a72923dca021’, ‘timestamp’: ‘2024-11-27 03:59:33.053659’, ‘data’: [‘Alice send Bob 200 coin’, ‘Bob send Chen 2000 coin’], ‘validator’: ‘E’, ‘hash’: ‘120255b4707e317e599eff7183b73e31bfc691d71ca987d8186a854c91e5d1bd’}

うーん、なるほどな〜 というところか…