ARST打卡第86周[86/521]

Algorithm

LeetCode/205_同构字符串

Review

克服上瘾的3条准则

一、你需要一个爱好,这能带来美好的情绪
二、照顾好自己的身体,养成健康的饮食习惯,并且定期锻炼
三、主动社交,联系老朋友,结识新朋友,你会感受到与他人连结的快乐感

Tips

Python防止listdir阻塞

CPython的实现os.listdir使用特定于平台的C库调用来读取目录的内容。在类似Unix的平台上,它们是opendir(3)and readdir(3),而在Windows上则使用FindFirstFileand FindNextFile。

在无法访问的网络文件系统的情况下,这些调用的行为将取决于操作系统。当使用Linux或Windows时,它们肯定会在系统命令(例如lshang)挂起的情况下挂起。为了防止任意长时间的停顿,可以使用专用框架,例如asyncio和twisted,它们使用非阻塞IO。但是,使用这些框架可能会让人望而生畏,并且通常需要在整个应用程序和整个程序中使用它们来构建事件驱动的模型。

确保存在网络文件系统时IO系统调用不会阻塞的一种更简单且对初学者友好的方法是使用线程。例如,这是一个safe_listdir返回目录内容的函数,或者None调用所花费的时间超过指定的超时时间:

1
2
3
4
5
6
7
8
9
10
11
import os, threading

def safe_listdir(directory, timeout):
contents = []
t = threading.Thread(target=lambda: contents.extend(os.listdir(directory)))
t.daemon = True # don't delay program's exit
t.start()
t.join(timeout)
if t.is_alive():
return None # timeout
return contents

在Python 3中,可以使用出色的concurrent.futures软件包。它不仅简化了实现,而且还自动限制了多次safe_listdir调用时创建的线程的数量,并确保将引发的异常os.listdir正确传播到调用者:

1
2
3
4
5
6
7
8
9
import os, concurrent.futures
pool = concurrent.futures.ThreadPoolExecutor()

def safe_listdir(directory, timeout):
future = pool.submit(os.listdir, directory)
try:
return future.result(timeout)
except concurrent.futures.TimeoutError:
return None # timeout

参考

os.listdir可以挂在网络驱动器上吗?它使用什么系统调用?

Share

Pyhton防止listdir阻塞进阶

使用超时装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# coding : utf-8
import sys
import threading
from time import sleep, time

class KThread(threading.Thread):
"""Subclass of threading.Thread, with a kill() method."""
def __init__(self, *args, **kwargs):
threading.Thread.__init__(self, *args, **kwargs)
self.killed = False
def start(self):
"""Start the thread."""
self.__run_backup = self.run
"""Force the Thread to install our trace."""
self.run = self.__run
threading.Thread.start(self)
def __run(self):
"""Hacked run function, which installs the trace."""
sys.settrace(self.globaltrace)
self.__run_backup()
self.run = self.__run_backup
def globaltrace(self, frame, why, arg):
if why == 'call':
return self.localtrace
else:
return None
def localtrace(self, frame, why, arg):
if self.killed:
if why == 'line':
raise SystemExit()
return self.localtrace
def kill(self):
self.killed = True

def list_file_timeout(seconds):
def timeout_decorator(func):
def _new_func(oldfunc, result, oldfunc_args, oldfunc_kwargs):
result.append(oldfunc(*oldfunc_args, **oldfunc_kwargs))
def _(*args, **kwargs):
result = []
'''create new args for _new_funcbecause
we want to get the func return val to result list
'''
new_kwargs = {
'oldfunc': func,
'result': result,
'oldfunc_args': args,
'oldfunc_kwargs': kwargs
}
thd = KThread(target=_new_func, args=(), kwargs=new_kwargs)
thd.start()
thd.join(seconds)
alive = thd.isAlive()
'''kill the child thread'''
thd.kill()
if alive:
alert_exce = u'list_file timeout for [%d s].' % seconds
# LOG.error(alert_exce)
print alert_exce
else:
return result[0]
_.__name__ = func.__name__
_.__doc__ = func.__doc__
return _
return timeout_decorator

class Foo:
TEST = 5

@list_file_timeout(TEST)
def list_file(self):
sleep(10)


foo = Foo()
foo.list_file()

单线程生成文件,并上传到S3桶中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
vim gen.sh

#!/bin/bash
fmt=output.%05d
cd lm

for i in $(seq 1 3)
do
head -c 512K /dev/urandom > `printf $fmt $i`
done


# 然后配置s3
# 配置
# endpoint是 ip:port , port可能是nginx网关,也可以直接是对应服务的port
s3cmd --configure \
--access_key=<access_key> \
--secret_key=<secret_key> \
--region=<region> \
--host=<endpoint> \
--host-bucket=<endpoint> \
--no-ssl

# 上传
s3cmd put lm s3://lm-noscan-bk --recursive

优化: vdbench 多线程生成文件