/tmp/duangsuse.sock
23 subscribers
303 photos
3 videos
92 files
337 links
从 duangsuse::Echo (@dsuse) 跟进出来的分支,将在作者恢复原帐号访问的时候合并删除。
Download Telegram
#Java 下面我会对 Promise 进行 Jawa 建模,过后有神秘分享哦(非技术向(跑,其实不值得期待

什么是 Promise 呢?英文中 Promise 的意思是保证。这里的 Promise 的意思则是 ECMAScript 6 新推出异步编程的一项特性。

异步编程是什么? Android 开发者会举出一种简单例子:

Button.OnClickListener exitApplication = (_) -> { finish(); };
assert exitApplication == new Button.OnClickListener() {
@Override void onClick(View _) { this.finish(); }
};
btnExit.setOnClickListener(exitApplication);

finish() 是 Activity 的方法,它标记当前活动状态为已结束。
别的例子,AsyncTask 封装(还有一个

class AsyncTask<R>(work: () -> R): AsyncTask<Void, Nothing, R> {
private var result: R
var onResult: Function<R, *>?
override fun doInBackground(vararg parms: Void) { result = work() }
override fun onPostExecute(result: R) = onResult?.invoke(result)
}

val dl = AsyncTask { downloadUrl("https://baidu.com/favicon.ico") }
dl.onResult = { println(it.size) }
dl.execute()

Web stackholder 则会举出更简单的例子(因为浏览器环境毕竟和 app 不同的原因,权限控制有区别,请大家忽视处理上的一些区别...):

btnExit.onclick = () => window.close();

Qt 和 GObject 的开发者则会使用 Signal & slots

connect(btnExit, SIGNAL(onClick()), this, SLOT(closeAllWindows()));

C# 的开发者会使用 C# 的 Event +=

btnExit.click += () => Environment.Exit(0);

最直白的例子还是 C/C++ 使用 Signal 的时候,此时没有那么多额外的东西干扰视线(比如对象对数据的封装,有时候可以把对象理解为操作被抽提的模块)

#include <csignal>
#include <iostream>

using namespace std;

void doTrapSigInt() {
signal(SIGINT, [](int s) { cout << "SIGINT ("<<s<<") Received" << endl; });
}

[[noreturn]] int main() {
doTrapSigInt();
for(;;){}
}

当然最最直白的特性还是为特定机器编程时设置的 interrupt 处理器(跑
不要忘了,最终执行你程序的还是机器处理器,所以所谓『异步』还是机器提供的特性。
『异步』,有时候是从其他『线程』在做的处理,但多数情况下都和处理器中断有关。

为了演示方便和篇幅考虑,我选择用汇编给 x86 DOS 写类似上面的那个例子... 按下按键的时候就(越过 DOS 操作系统地)输出字符

https://wiki.osdev.org/Interrupts
http://spike.scu.edu.au/~barry/interrupts.html#ah02

bits 16

kbdval db 0x60
pic db 0x20
sys db 0x21
DOS_displaychar db 0x02
ivt_kbd db 9*4

_entry:
cli
mov word [ivt_kbd], kbdInt
mov word [ivt_kbd+2], 0
sti

mov al, 'D'; call putc_al
mov al, 'o'; call putc_al
mov al, 'n'; call putc_al
mov al, 'e'; call putc_al

mainloop:
hlt ; wait next interrupt
jmp mainloop

kbdInt:
push eax
in al, kbdval
call putc_al

mov al, pic
out pic, al

pop eax
iret

putc_al:
mov ah, DOS_displaychar
mov dl, al
call sys
ret

啊又跑偏了... 上面的程序在 DOSBox 里测试是失败的 不知道为什么...(求不喷没用 marco)

总之,我们可以认为『异步』就是不在我们的『串行』程序逻辑执行过程中被处理的东西,它有一个额外的处理进程。
而异步和我们有个毛线的关系?关系只在不同的『处理进程』发生联系的时候出现,例如需要有某种『信号』在线程间传递,打断正常的串行执行(或许这种打断是被预期的,也可能并没用打断,而是主动执行分派),让异步信号得到处理。

这是『异步信号』(类似 Qt 的信号/插槽)模型,比较通用。因为其他进程的执行状态,抽象成信号也是很直白的。不过注意这个『信号』是抽象的,不代表信号就应该怎么样地(例如在『线程』 A)被处理。
当然,也有『回调』,实际上就是把信号处理固定在任务执行的线程进行了(

以上是信号的抽象,可以认为是一种 Thenable, 只有一个方法 then(Listener),反正信号除了可以『监听』也没啥用了。

所谓 Promise,它的意思是这项特性『保证』了异步任务的状态转移存在某种规律:

states pending (0), resolved, rejected
pending (resolve)~> resolved (then)
pending (reject)~> rejected (catch)

初始状态是 pending,代表任务正在执行
new Promise((resolve, reject) => { resolve(1) }).then((it) => console.log(it))
pending 时通过 resolve 箭头,我们状态转移到了 resolved 状态,并且 then 将会接收到此信号
pending 时通过 reject 箭头,我们状态转移到了 rejected 状态,并且 catch 将会接收到此信号
除了这样以外没用其他可能,不能从 resolved 变回 pending 或者转移到 rejected,这就是 Promise 的含义。

那么终于进入正题了:Java 里该如何抽象?

interface Thenable<R> { void then(Consumer<? super R> next); }

interface Failable<R> extends Thenable<R> { void then(Consumer<? super Result<R>> failable_next); }

这是我们对最基础『异步任务』的抽象:可以失败的东西
然后有个 abstract class Promise 来扩展它
还应该实现 Promise.resolve, Promise.all, Promise.race, Promise#done, Promise#catch 方法 🤔
吃上了 Eclipse Java(
目前我在写这个玩意,写完后会发的
(土拨鼠的尖叫)啊啊啊啊啊.... Jawa 这个 type wildcard 也太辣鸡了,Kotlin 有声明处型变呢
#Java 啊啊啊啊(土拨鼠尖叫) 真的是脑残至极...
艹,看看能不能用,全 TMD 是 raw types & cast
Maybe<T>
🤔 Java 有个不好就是有时候太莫名其妙了,比如方法的 final 修饰、interfaceabstract 修饰等等,语法上就不应该存在
@FunctionalInterface 的幻想破灭了... 现在这个样子很辣鸡。
其实 Promise 还可以 flatMap 的,这样就可以:

String title = Promise
.begin(() -> newClientCall(Requests.get("https://example.org")))
.map((r) -> r.body())
.flatMap((b) -> b.match("<title>(.*)</title>"))
;

我确认功能以后会添加...
emmm... 刚才我想的大概是两个 Promise 拼接的样子吧..

Promise.begin(readFile("foo.txt"))
.andThen((r) -> newClientCall(DELETE(r)));

这种
不好... 是并发数据竞争问题...
傻了 或许可以用 monitor (synchronized 块)
(好像不能在 lambda 表达式里用

乱序执行的情况下,我的算法可能会多次往相同的位置写入某个 o
因为希望 Android 上也能用,我不能使用 JDK 的 concurrent utils...

有没有更好的方法呢
算了...
This media is not supported in your browser
VIEW IN TELEGRAM
啊,想到一个方法,Android 应该提供了线程安全的 Vector
等等... 可是不能使用 AtomicInteger,没用...
那我就只好让要用的大牛自己实现安全的版本了...
一定会写完的!写完了就会继续讲下面的事情哦。
真香,我也想写一个,思路想到了
/tmp/duangsuse.sock
Promise-Java.zip
其实我的意思本来是 Promise 任务是抽象的... 现在好像为了 @FunctionalInterface 不得不额外弄了个 Working 出来

所以我得负责进行异步操作分配 Executor 了...
单元测试... 我会写一点。
文档在测试完代码可以用之后也会写的
+1 Tests wrote
🤔 #Java #task 打算写一个上下文依赖注入(CDI)库,不过不是最近的事情

就起名叫做 Pot,钦定以下使用:

@pot abstract class Door {
@implicit public Lock locker;
public void open(String password) {
locker.checkPass(password);
openDoor();
}
private abstract void openDoor();
}

这是最基本的 Bean 用法,除了使用 public @implicit, 还可以用

private @implicit Lock locker;
public @give(Lock.class) setLocker(Lock lck) { locker = lck; }

Door(@give Lock lck) { lock = lck; }

此外,还可以

private Dependency<Lock> locker;

然后在 constructor 里

locker.ensure();

当然 pot 的 annotation processor 可以自动生成这种 constructor

Door() { this.injectDependencies(); }

Pot 当然是全局的,要不然也无法提供注入了
也打算支持使用 Singleton 模式

Pot 应该支持依赖链条(比如 Lock 有无参数架构器,实例还有别的依赖)
此外,循环依赖也应该被良好的处理(创建先后有日志输出)

class Van {
@ImplicitContext
public @interface DeepDarkHome {}
@ImplicitContext
public @interface Jam {}
}

@DeepDarkHome
@pot abstract class VanHomeDoor {
@implicit public Lock locker; // with context DeepDarkHome
public void open(String password) {
locker.checkPass(password);
openDoor();
locker = Pot.refresh(locker, Jam.class); // dropped, re-created with context Jam
locker = Pot.rebuild(lock, VanHomeDoor.class) // re-created
}
private abstract void openDoor();
}

🤔 这样?我不是很熟悉 CDI

Pot 可以支持两种创建注入对象的方法:
1. @provides(...) 标记的方法
2. @provides(...) 标记的架构器
可以选择

Pot 支持按照反射参数化类型查找实例

@implicit List<User> storageUserList;
...
@provides List<User> loadUserListFromFile() {...}
...
@provides(cacheRefresh = 0) List<User> refreshUserListFromFile() {...}

需要创建组件(pot) 的实例时:
door_Jam = Pot.make(DarkDoor.class, "Jam");
door_Home = Pot.make(DarkDoor.class, "F**king comming");

当然关于那个 CDI 的 C 我不是很确定,以后可能再了解
不过其实组件化到这个地步也是足够的...