go相关的,推荐draveness大佬的博客啦 https://draveness.me
Tsuko

- 注册于 2018年5月24日
大佬牛逼
- 已编辑
补充一下,无WSGI的视角:
http http --------> Nginx --------> webserver
WSGI:
http http WSGI\ASGI --------> Nginx --------> web server ------------> Python Object
0x0001
gq老哥的回答有很大帮助!其实主要是WSGI的粒度与我的经验有差异。WSGI的文章老是提到:
WSGI is an interface between web server and web app.
我觉得很奇怪:web server 和 web app不是同一个东西吗?后来看多几篇文章,大概了解这个server是接受请求和返回请求的程序,web app指的是处理具体业务的Python对象。从uvicorn的”奇怪“用法可以看出:
# main.py from fastapi import FastAPI app = FastAPI()
通过
uvicorn main:app --reload
启动服务器。这里uvicorn(web server)直接找到main.py的app这个全局变量作为web app,不是整个main.py。在我接触过的框架(gin, actix-web)没有这样做法,所以一时间感到很奇怪。- 已编辑
不太懂为什么会产生WSGI这个东西?
现在是: Browser -> Nginx -> uvicorn -> WebApp.
直接 Browser -> Nginx -> WebApp不行吗?是不是将某些网络功能从APP offload到WSGI服务器上了?APP就负责业务逻辑?
有什么比较好的资料、文章讲讲这个东西的必要性\没有会产生什么问题?
需求:有一个不断生长的有向无环图,有向无环图的生长依赖外部事件源,生长规律是不可计算的。
请问有什么实现方案吗?语言、库、软件都可以,动画效果其次,简单易上手最好(:
可以啊!建议去掉“后端”定语。期待来个数据库内核开发路线图?@iosmanthus
- 已编辑
知识点+1.
突然想起同学在极客云上租了几台机器,发现不同机器的内网ip一样,不同机器通过预留的23XXX端口进行通信,比如A与B通信:172.0.0.1:23001 -> 172.0.0.1:23002, 看来是用了IP anycast?
有点好奇极客云为啥要这样做,为啥不是创建一个私有网络然后一台机器一个ip,有大佬了解这方面吗?
- 于 春招有车吗?
- 于 春招有车吗?
如题,有没有云原生相关的工作?
马克一波
- 已编辑
woc!尴尬地发现包发错,发给自己了。。
把:.map(|(self_addr, target)| async move { let ((addr, listener), tar) = (self_addr, target); let d = Duration::from_secs(delay_secs); // ... }
改为
.map(|((target, listener), self_addr)| async move { // ... }
果然是“先把问题复述一遍,然后就能自己找到自己的愚蠢错误了”。。。
- 已编辑
最近用Rust写了个pinger和ponger,pinger每5s向ponger发一个udp包, ponger会把这个消息打印到终端。
但是发现pinger一直在自顾自地ping,ponger那里一条日志都没收到。
先用tcpdump抓包
sudo tcpdump -i lo port 8888
:tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes 10:50:34.290607 IP localhost.8888 > localhost.8888: UDP, length 24 10:50:39.291118 IP localhost.8888 > localhost.8888: UDP, length 24 10:50:44.291684 IP localhost.8888 > localhost.8888: UDP, length 24 10:50:49.292292 IP localhost.8888 > localhost.8888: UDP, length 24 10:50:54.292864 IP localhost.8888 > localhost.8888: UDP, length 24
sudo tcpdump -i lo port 6666
抓ponger,发现没有收到包消息。nc -z -u -v localhost 6666
同时抓ponger,发现ponger可以正常接发包。
不知道哪里出问题了,请教各位。。最后附上代码:
// Pinger use async_std::net::{SocketAddr, UdpSocket}; use futures_timer::Delay; use log::{error, info}; use simplelog::{CombinedLogger, Config, LevelFilter, TermLogger, TerminalMode}; use futures::future::join_all; use std::{io::Read, sync::Arc, time::Duration}; pub struct UdpPinger { // targets: pub targets: Vec<SocketAddr>, pub delay_secs: u64, } impl UdpPinger { pub async fn run(self) -> std::io::Result<()> { let listener = async_std::net::UdpSocket::bind("127.0.0.1:8888") .await .expect("couldn't bind"); let listener: Arc<UdpSocket> = Arc::new(listener); let self_addr = listener.local_addr().unwrap().to_string(); let delay_secs = self.delay_secs; join_all( self.targets .into_iter() .zip([listener].iter().cloned()) .zip([self_addr].iter().cloned()) .map(|(self_addr, target)| async move { let ((addr, listener), tar) = (self_addr, target); let d = Duration::from_secs(delay_secs); loop { // std::thread::sleep(std::time::Duration::from_secs(1)); match listener .send_to(format!("ping from {}", &addr).as_bytes(), &tar) .await { Err(e) => error!("{:?}", e.to_string()), Ok(_) => info!("ping {}", &addr), } Delay::new(d).await; } }), ) .await; // println!("done"); info!("pinger done"); Ok(()) } } fn main() { let _ = CombinedLogger::init(vec![TermLogger::new( LevelFilter::Info, Config::default(), TerminalMode::Mixed, )]); info!( "working at {}", std::env::current_dir().unwrap().to_str().unwrap() ); match std::fs::File::open("./conf/targets") { Ok(mut f) => { let mut s = String::new(); match f.read_to_string(&mut s) { Ok(_) => { async_std::task::block_on( UdpPinger { targets: s .split_whitespace() .map(|tar| tar.parse().unwrap()) .collect(), delay_secs: 5, } .run(), ) .unwrap(); } Err(e) => error!("{}", e.to_string()), } } Err(e) => error!("{}", e.to_string()), } }
// Ponger use simplelog::{CombinedLogger, Config, LevelFilter, TermLogger, TerminalMode}; use async_std::net::SocketAddr; use log::info; pub struct FakeHost { pub addr: SocketAddr, } impl FakeHost { pub async fn run(self) -> std::io::Result<()> { let listener = async_std::net::UdpSocket::bind(self.addr).await?; let quit = false; let mut buf = [0u8; 512]; info!("ponger up {}", listener.local_addr().unwrap().to_string()); while !quit { let (sz, peer) = listener.recv_from(&mut buf).await?; info!( "from {}: {}", peer.to_string(), String::from_utf8_lossy(&buf[..sz]) ); // echo //listener.send_to(&buf[..sz], peer).await?; } info!("ponger done"); Ok(()) } } fn main() { let _ = CombinedLogger::init(vec![TermLogger::new( LevelFilter::Info, Config::default(), TerminalMode::Mixed, )]); async_std::task::block_on( FakeHost { addr: "127.0.0.1:6666".parse().unwrap(), } .run(), ) .unwrap(); }
- 已编辑
Thread通过中间层ThreadLocal去访问ThreadLocalMap, Map弱引用了ThreadLocal作为key。
ThreadLocal被GC但是Map中对应的Slot没有被释放。可以通过:- 定期删除
- 延迟到某事件发生时删除
Map采用后者. 在set()/get()/remove()中会删除无效的slot. 这也是大多数文章提到的,然后点到为止了(??)
我猜应该是其他threadLocal调用 remove()会告诉Map去遍历删除无效的key value.- 已编辑
对Java不熟悉,但是在Golang中通过条件变量Cond。看了一下这篇文章,发现Condition使用方式跟go的sync.Cond十分类似。由此推断条件变量的用法应该是较为通用的。
首先,条件变量是跟某个锁关联的,在Java里面类似这样:
public Lock lock = new ReentrantLock(); public Condition condition = lock.newCondition();
在Go中类似这样:
var mx sync.Cond cond := sync.NewCond(&mx)
其次,假设要实现:p()为真时通知所有等待变量,那么sync.Cond的用法应该是这样:
func f1(){ mx.Lock() for ! p(){ cond.Wait() } mx.Unlock() }
也就是条件变量被mx的加锁解锁包住。这是因为Wait()的底层实现:
- 先解锁mx, 所以你在Wait之间先要加锁
- 阻塞
- 被唤醒
- 再加锁
- 再检查 P()是否成立
如果P()成立,那么将不会进入循环,而此时已经加锁了,所以你要解锁。
所以我推测你的问题在:await()已经获得锁了,但是在下一次loop时还要获得锁,因此导致了死锁。用条件变量最好按照这个范式来。- 于 论某德阳神秘乱码
哈哈,语言学奥赛