默认分类
只是一个默认分类

Js 中的 CSP(Communicating Sequential Processes)

dd839ff45691d9737ce18a35a1f27f5c.jpg

什么是 CSP(Communicating Sequential Processes)?

CSP是由托尼霍尔在1978年发表的一种形式语言规范,中文翻译为通信顺序进程,用于描述并发系统中的通信模式。Go语言原生支持,Clojure有core.async。

并发的系统的实现

为了设计并发系统,并发进程/任务/作业/应用程序必须能够进行通信。广泛采用的方法是使用公共存储(数据源)。但是,如果数据源以不需要的顺序写入和读取,则问题是竞争条件和不可靠性。

  • 公共存储

    • Threads
    • Locks
    • 互斥 Mutexes
  • 消息传递 (CSP and Actor Model)

    • Processes
    • Messages
    • No shared data

并发不是并行

例程A将消息放入某个通道。然后停止,直到例程B准备好接收该消息。在服用它之后,B运行直到它接下来接受指令并且退后,因此常规A可以再次运行并且它可以无休止地运行。

没有并行性的并发性:不是操作系统的线程,而是将一个操作系统线程分段使用。

csp_illustration2.png

下面使用js-csp中的一个例子,两个process之间打乒乓球:

import {
 go,
 chan,
 take,
 put,
} from 'js-csp'
const ping = chan()
const pong = chan()
go(function * () {
 yield take(ping)
 console.log('ping')
 yield put(pong, true)
})
go(function * () {
 yield take(pong)
 console.log('pong')
 yield put(ping, true)
})
put(ping, true)
// > 'ping'
// > 'pong'
// > 'ping'
// > 'pong'
// > 'ping'
// > 'pong'
...

CSP与 Actor 模型

Actor模型,又叫参与者模型,其”一切皆参与者(actor)”的理念与面向对象编程的“一切皆是对象”类似,但是面向对象编程中对象的交互通常是顺序执行的(占用的是调用方的时间片,是否并发由调用方决定),而Actor模型中actor的交互是并行执行的(不占用调用方的时间片,是否并发由自己决定)。

从actor自身来说,它的行为模式可简化为:

  • 发送消息给其它的actor
  • 接收并处理消息,更新自己的状态
  • 创建其它的actor

区别

  • Actor中实体和通信介质是紧耦合的,一个Actor持有一个Mailbox,而CSP中process和channel是解耦的,没有从属关系。从这一层来说,CSP更加灵活
  • Actor模型中actor是主体,mailbox是匿名的,CSP模型中channel是主体,process是匿名的。从这一层来说,由于Actor不关心通信介质,底层通信对应用层是透明的。因此在分布式和容错方面更有优势。

关键概念与实现

  • 顺序处理(processes)
  • 通过通道(channel)进行同步通信
  • 通道的多路复用与交替

channel 是一个队列,Processes 通过channel进行通信,Processes 可以暂停来等待 channel 中的值。
processer 是一个Pull模型的迭代器,它不断从 channel 取出最新的值,如果没有值就暂停执行。

Processes

async function process (inChannel, outChannel) {
  while (true) {
    const msg = await inChannel.take();
    // do stuff with msg
    await outChannel.put(res);
  }
};

我们使用[Symbol.asyncIterator]channer成为可迭代对象,然后使用for-await-of语法会更加简洁,同时通过这个while(true)不难理解 process 一直从channer拉取数据:

public async *[Symbol.asyncIterator](): AsyncIterableIterator<T> {
    while (true) {
        yield await this.take();
    }
}
async function process (inChannel, outChannel) {
  for await(const msg of inChannel) {
    // do stuff with msg
    await outChannel.put(res);
  }
};

Channel

在Channel中实现了messages putters takers racers 这几个队列。
put 操作返回一个Promise,在该Promise中 首先将传入的参数放到messages,然后将resolve函数放到putters,然后判断takers队列是否有值。

  • 如果已经有taker 或racers等待消息,则返回的承诺将立即得到解决
  • 如果taker 和racers都在等待消息,则优先权将给予将检索该消息的接受者

可以对channel队列进行操作,例如过滤,遍历等等,多个channel之间还可以广播,或者合并。

更多资料

https://arild.github.io/csp-presentation/
https://github.com/jfet97/csp
https://pusher.com/sessions/meetup/the-js-roundabout/csp-in-js
Javascript中的CSP快速入门

解决GPT分区无法安装系统问题

重装系统时遇到:“windows无法安装到这个磁盘。选中的磁盘采用GPT分区形式”。按照提示更换分区格式可以解决问题,但是更换分区格式需要格式化整张磁盘。肯定不能这么做...

要解决这个问题,我们先要需要理清 GPT与MBR、UEFI与BIOS 这几个名词的区别。

磁盘分区格式:GPT与MBR

随着磁盘容量越来越大,传统的MBR分区表(主引导记录)只能识别磁盘前面的2.2TB左右的空间,已经不能满足大容量磁盘的需求。因此,才有了GPT(全局唯一标识分区表)。GPT可以支持无限个分区,微软目前的限定是128个。MBR最多4个主分区,超过4个再分区只能通过逻辑分区。

UEFI与BIOS

Win8以后笔记本默认是UEFI+GPT,想要从GPT磁盘启动,主板的芯片组必须支持UEFIUEFI可用鼠标操作图形界面,不再是枯燥的蓝底白字的英文。另外UEFI减少了BIOS自检的步骤,从而加快了启动时间。

Add Boot Option(添加引导选项)

在选择UEFI后并没有出现U盘,所以我们需要手动添加引导选项。进入BIOS后找到Add Boot Option选项,首先给你想要添加的启动项起个名字,再选择你的U盘后会出现一个文件目录菜单可以逐级选择,有的BIOS需要手动输入路径,efi文件位置在\EFI\BOOT\SHELLX64.efi

最后通过切换引导方式,手动新建启动项解决了问题。

C++ 读取TXT中的数字到vector容器

读取TXT文件中的数字到一个二维vector容器,也可以将vector输出到一个TXT文件中。
这段程序主要有五个函数readFile,split,transToNum,transVector,output

  1. split分割字符串
  2. readFile调用split并返回一个二维字符串向量
  3. transToNum将字符串转换为int或double。
  4. transVector将二维字符串向量转换为二维int或double向量。
  5. output把一维或二维vector输出到txt(文件名默认为output.txt)

使用示例

TXT文件:

1 3.12 3
-1 1 1 3.123 4.11

调用方法:

vector<vector<int> > intData;
getTXTNum("input.txt", intData);
output(intData);

完整程序代码

#include <iostream>
#include <vector>
#include <fstream>
#include <stdlib.h>

using namespace std;

vector<vector<string> > readFile(string filePath, char tag = ' ');

vector<string> split(string inputString, char tag);

template<typename T>
void transToNum(string inputString, T *result);

template<typename T>
void transVector(vector<vector<string> > data, vector<vector<T> > &intData);

template<typename T>
void getTXTNum(string filePath, vector<vector<T> > &data);

template<typename T>
void output(vector<vector<T> > data, const  char* outputName="output.txt");

template<typename T>
void output(vector<T> data, const char* outputName="output.txt");


vector<vector<string> > readFile(string filePath, char tag) {
    ifstream fileReader(filePath.c_str(), ios::in);
    if (!fileReader) {
        cerr << filePath << " not exist!\n";
        exit(1);
    }
    vector<vector<string> > data;
    string linestring;
    while (getline(fileReader, linestring)) {
        data.push_back(split(linestring, tag));
    }
    return data;
}

vector<string> split(string inputString, char tag) {
    int length = inputString.length();
    unsigned int start = 0;
    vector<string> line;
    for (unsigned int i = 0; i < length; i++) {
        string sub;
        if (inputString[i] == tag) {
            sub = inputString.substr(start, i - start);
            line.push_back(sub);
            start = i + 1;
        } else if (i == length - 1) {
            sub = inputString.substr(start, i - start + 1);
            line.push_back(sub);
        }
    }
    return line;
}

char *getType(int x) {
    return (char *) "int";
}

char *getType(double x) {
    return (char *) "double";
}

char *getType(float x) {
    return (char *) "float";
}

template<typename T>
void transToNum(string inputString, T *result) {
    const char *p = inputString.c_str();
    char *type = getType(*result);
    if (type == "int")
        *result = atoi(p);
    else
        *result = atof(p);
}

template<typename T>
void transVector(vector<vector<string> > data, vector<vector<T> > &intData) {
    vector<vector<string> >::iterator iter = data.begin();
    for (; iter != data.end(); iter++) {
        vector<string> line = *iter;
        vector<string>::iterator lineIter = line.begin();

        vector<T> intLine;
        for (; lineIter != line.end(); lineIter++) {
            T result;
            transToNum(*lineIter, &result);
            intLine.push_back(result);
        }
        intData.push_back(intLine);
    }
}

template<typename T>
void getTXTNum(string filePath, vector<vector<T> > &data) {
    transVector(readFile(filePath), data);
}

template<typename T>
void output(vector<vector<T> > data, const  char* outputName) {
    ofstream outTxt;
    outTxt.open("output.txt",ios::trunc);
    int sizeA = data.size();
    for(int i=0;i<sizeA;i++){
        int sizeB = data[i].size();
        for(int j=0;j<sizeB;j++){
            outTxt<<data[i][j]<<" ";
        }
        outTxt<<endl;
    }    
}

template<typename T>
void output(vector<T> data, const char* outputName) {
    ofstream outTxt;
    outTxt.open("output.txt",ios::trunc);
    int sizeA = data.size();
    for(int i=0;i<sizeA;i++){
        outTxt<<data[i]<<" ";
    }
    outTxt<<endl;
}

参考文章:
c++ 读取数值文件到数组中

在怀疑的时代,人们的行动目标要放得长远些

随着信仰之光的暗淡,人们的目光变得越来越短钱,行动的目标似乎似乎就摆在眼前。
...
因此在在怀疑盛行的时代,最可怕的是人们在追逐每天变化的欲望,完全放弃经过长时间努力才能获得的事物,最终无法建立任何伟大、稳定与持久的事业。
如果这样一个民族的社会状况是民主的,那么我所指出的危险还要加剧。

看到这,我松了一口气~

机器怎么学习

机器学习入门,如果上来就看各种算法,什么神经网络,卷积神经网络,我保证你会云里雾里。最好的方法其实是在站在顶层上了解各种概念,不要纠结于具体实现,这样对机器学习有一个整体的概念就不会迷失方向。要不你想参加什么培训班,都可能被忽悠。

人工智能、机器学习与深度学习?

先对这些名词了解。

人工智能 > 机器学习 > 深度学习

人工智能范围很广,只要是能做某些智能活动的程序都是人工智能。人类的智能活动可以是语言、运动、知觉、学习等等,语言对应的就是自然语言处理,运动对应机器人,知觉可以是语音识别,其中的学习就是机器学习了。深度学习是机器学习的一个分支,你应该听说过深度人工神经网络、卷积神经网络等等,这些就属于深度学习,在入门阶段你可以把深度学习理解成多层的神经网络,AlphaGo就用到了深度学习相关算法。

机器如何学习

谈到学习,当然要有老师先训练,即便人类也不可能从一无所知的小孩自学成才,而且学会了公式还要做习题巩固。所以机器学习当然也需要先人为的进行训练,人类学习的训练方式可以是做习题,机器的学习的训练方式就是数据。我们根据数据是否有标签能进一步划分学习方法,这个标签就相当于人类学习用的习题的答案,如果数据都有标签就是监督式学习,没有标签就是无监督式学习,数据有的有标签有的没有那就是半监督式学习。
当然作了题不给我答案,我只能把题目分个类了。

一、无监督式学习

非监督式学习问题可以进一步分为聚类问题和关联问题。(注意聚类与分类的区别,就像化学中的相似相溶原理,自主地想属于自己的集合靠拢;而分类则是我们根据一定的标准进行划区分)

聚类问题:聚类学习问题指的是我们想在数据中发现内在的分组,比如以购买行为对顾客进行分组。
关联问题:关联问题学习问题指的是我们想发现数据的各部分之间的联系和规则,例如购买X物品的顾客也喜欢购买Y物品。
一些流行的非监督式学习算法的例子:

聚类问题的k-means算法
关联规则学习问题中的Apriori算法

二、监督式学习

在监督式学习下,输入数据被称为“训练数据”,每组训练数据有一个明确的标识或结果,如对防垃圾邮件系统中“垃圾邮件”“非垃圾邮件”,对手写数字识别中的“1“,”2“,”3“,”4“等。在建立预测模型的时候,监督式学习建立一个学习过程,将预测结果与“训练数据”的实际结果进行比较,不断的调整预测模型,直到模型的预测结果达到一个预期的准确率。监督式学习的常见应用场景如分类问题和回归问题。

通常,这类预测问题可以用回归模型(regression)进行解决,回归模型定义了输入与输出的关系,输入即现有知识,而输出则为预测。

常见算法有逻辑回归(Logistic Regression)和反向传递神经网络(Back Propagation Neural Network)