统计学习方法 决策树 Ch5
#!/usr/bin/env python3
# thread.py
# -*- coding: utf-8 -*-
__author__ = 'bravo'
import os,time, random
from multiprocessing import Process
from multiprocessing import Pool
import threading
import os
lock = threading.Lock()
def subproc(name):
start = time.time();
print('%s Child(%d) created' % (name,os.getpid()))
time.sleep(random.random()*3)
end = time.time()
print('%s Child(%d) lasts %02f times' % (name,os.getpid(),end-start))
def fork_test():
print('start')
pid = os.fork()
if(pid == 0):
print('child ', os.getpid(),'with parenet',os.getppid())
elif (pid > 0):
print('parent')
else:
print('error')
def pool_test():
print(threading.current_thread().name)
print('Parent(%d)' % os.getpid())
p = Pool(1000)
for i in range(1000):
p.apply_async(subproc,(i,))
p.close()
p.join()
print('All done')
def thread_test():
t = threading.Thread(target=pool_test,name='thread for pool')
t.start()
t.join()
ev = threading.Event()
def gogogo(item):
index,ev = item
if index != 9:
print('wait',index)
ev.wait()
else:
print('set')
ev.set()
time.sleep(index)
print('item',index)
def start_thread(obj):
print(obj.isalive())
return
if __name__ == '__main__':
# thread prepare 注意参数如何传递的,线程函数不能用用*arg **kwds来作参数
thread_l = [threading.Thread(target = gogogo,args = ([i,ev],)) \
for i in range(10)]
# lambda同时启动, map后得到的是iterator,需要list下才真正执行
list(map(lambda obj:obj.join(),thread_l))
#fork_test()
#poll_test()
# thread_test()
input('end')
#include <iostream>
class A {static int s;};
class B: virtual public A {};
class C: virtual public A {};
class D: public B, public C{char a;};
int main(int argc , char* argv[])
{
std::cout << "A: " << sizeof(A) << std::endl;
std::cout << "B: " << sizeof(B) << std::endl;
std::cout << "C: " << sizeof(C) << std::endl;
std::cout << "D: " << sizeof(D) << std::endl;
return 0;
}
ubuntu 64bits g++ 5.4.0 结果:
A: 1 // static变量不占object的内存!
B: 8
C: 8
D: 24 //8 + 8 + 1 + 7
A: 编译器插入 1 字节,表明 object 的唯一地址用的;
B:C 加上 vptr,但是又不需要那 1 字节了?
D: 继承 ,两个 vptr !(virtual public 不起作用?)
结论: 编译器行为…很不好说.可能自己插入一些字节, 另外还有可能有需要补齐也占用 object 的字节.
class E {
public:
virtual ~E(){}
int a;
char b;
void * c;
virtual void foo() {}
};
E e;
std::cout << "E: " << sizeof(E) << std::endl;
std::cout << "e.addr " << &e << std::endl;
std::cout << "e.a " << &(e.a) << std::endl;
std::cout << "e.b " << &(e.b) << std::endl;
std::cout << "e.c " << &(e.c) << std::endl;
结果是:
E: 24 = 8 +4 + 1 + 3 + 8
e.addr 0x7ffd47bb2c50
e.a 0x7ffd47bb2c58
e.b
e.c 0x7ffd47bb2c60
E 的大小为 size(vptr) + size(int) + size(char) + size(void*)=24.
但有的编译器, 不一定把 vptr 放在开头的位置.也可能放在结尾, a,b,c 这些 data member 的顺序也可能在任意位置.
一般来说就是 base class data member + derived class new data member.但是 data member 的布局也不是确定的,仍然取决于编译器.
多重继承,可能带来多重 padding,(如派生每次都多出一个 char 变量,需要补齐为 4),造成空间的浪费.
如果 base class 没有 vitural function ,而 drived class 有:
Base b;
Derived d & = b;
编译器得在编译器介入,为 d 插入 vptr.
#include <iostream>
class A {int m_a; char m_ca;};
class B {int m_b;};
class C :public A, public B { int m_c;};
int main(int argc , char* argv[])
{
A a;
B b;
C c;
A* pa = &c;
B* pb = &c;
std::cout << "c addr: " << &c << std::endl;
std::cout << "pa addr: " << pa << std::endl;
// pb = (B*)(&c + sizeof(A))
std::cout << "pb addr: " << pb << std::endl;
return 0;
}