Archive for 算法-编程

妮神教的,没看过标准的我只能猜测,不过开始猜测的还正确了 我在一个包文件里这么定义了一个常量 (defconstant +levels+ (vector :error :warning :info :debug)) load的时候说重复定义,这显然是不正确的,我其他地方都没定义过,显然后边那个值又计算了。我在群里问就是后边这个值是不是又计算了一次。 不过我不知道原因是load了多次导致的 妮神的讲解就是,加载到repl的时候会load多次,然后 就会定义多次,而常量不允许定义多次,cl的实现就会判断定义的时候后边的值是否eql,eql就通过,不eql就报错。而vector虽然是不变长的,但是还不是一个对象,执行两次不eql,所以会报错。 直接用defparameter定义的,包里边自己别修改一般不会有问题吧。

Continue

在妮神帮助下,学习了很多cl的知识,后边都总结一下。 本想晚上洗袜子,跑步。写代码写的上火,写了一晚上写了40行cl代码,四个宏,并且功能还没做完。想给框架先写个log模块的,用宏可以编译前判断log打印等级决定生成是否打印,现在整的完全不想写cl代码了[泪流满面] 洗洗睡,袜子明天起的早再洗 今天早上思路清晰多了,代码精简到34行.修复了一个bug。问题是修复了这个bug,展开式变成4行,没修复之前展开式只有一行,不爽 ,,四行的话和写个函数没啥区别了 昨晚上和今天早晨的微博,然后就不记录前后原因了。 说说怎么编译包。 首先要load 依赖包,不然会编译的时候找不到。 (ql:quickload "cl-async") 编译包的顺序,要先编译package.lisp并且load。不然编译别的文件会找不到你自己定义的包. (load (compile-file "package.lisp")) 之后按顺序编译其他文件 (load (compile-file "logging.lisp")) (load (compile-file "server.lisp")) 这样其实就可以执行代码了。不过退出repl从新加载的时候,顺序一样,要先load依赖包,然后loadpackage,最后load相关包文件。然后写代码测试。

Continue

今天本来想写点web框架代码,早早睡觉的,框架代码写了一点。发现测试时候load 然后执行,想文件多了没法搞了。先看看cl打包吧。 然后就查看过的书,找讲包的内容,发现很少。就一个defpackage,实用cl编程里边讲的多一点,注意事项很多,然并卵,写完发现一样不好用。 去群里求救,需要asdf这么个东西,起了个蛋疼名。之前用过但是不知道干嘛的,文档 https://www.common-lisp.net/project/asdf/asdf.html 首页有个有意思的地方Examples Download any of the many packages available through Quicklisp to see as many examples. 哈哈,不过文档里有。 看文档sbcl里边好像自带asdf,我装过quicklisp,并且启动repl的时候自动加载。可以直接使用(asdf:asdf-version)看到asdf的版本3.0.2 duang.asd

(in-package :asdf-user)

(asdf:defsystem duang
  :description "A simple Web Framework."
  :author "0x55aa "
  :license "BSD"
  :version "0.0.1"
  :depends-on (#:cl-async)
  :components ((:file "package")
               (:file "server")))
主要定义包的依赖关系 package.lisp
(defpackage :duang
  (:use :common-lisp :cl-async)
  (:nicknames dg)
  (:export #:start-server))
server.lisp
(in-package :duang)
(defun start-server () ())
然后代码的位置要能被sbcl发现,看文档可以自定义,等会儿看看quicklisp文档有没有。我直接放到~/quicklisp/local-projects/文件夹下了。 最后在repl里(asdf:load-system "duang") (dg:start-server)就行了 (require :duang) (load ) (ql:quickload "duang") 都行 这么点东西搞了一晚上

Continue

 资源多一点了,现在不到150万。种子搜索的速度不是太快,这一版和我之前用python写的不一样,之前用python写的再没做优化,内存占用还是高,不过速度快一点。 芭蕉细雨 使用sphinx做分词搜索种子信息,数据库使用postgresql,使用了redis。开始的时候使用postgresql自带的搜索进行搜索,速度已经非常好了,不过还是慢,换成专业搞搜索的就快了好多。 开始 长的要一两秒,到后来资源多了,需要十秒,我就从逻辑上进行优化,从开始就没有使用offset,我用id进行查询的分割,这种对于资源多的种子检索很好用,但是对于资源少的还是没办法。 换成sphinx,postgresql不需要单独使用一个表存储搜索字段,硬盘占用会少一点。python程序也不需要分词包,一下子占用内存少了很多。sphinx资源占用也少,并且速度就需要几十毫秒。

Continue

昨天下午写了一个postgresql访问接口库psycopg2的异步封装,这个库是支持异步请求postgresql的,所以只是简单的封装了一下。简介了torndb和一个网上写好的异步库momoko,又找到一个网上分享的ppt。写的时候直接用gen.coroutine装饰接口函数,这样我再models里写的时候直接yield query()就行了。 写完对tornado异步封装的代码也看了一些,有了一些理解,不过没有循序看。之前看到时候感觉太乱实在不想从新看了。先记录一下,可能很多错误。 future是保存的异步的结果,这个类是在concurrent.py文件里。 result()方法是返回结果,通过done()方法判断执行结束,就可以用result方法获得结果。 set_result()是设置结果,像gen.Task()就是调用一个带有callback参数的异步方法,返回future,变成为一个可以使用yield协程 的函数,对他就是个函数。2333 这个函数里边就使用了set_result()方法,Task这个函数其实不复杂写了那么多的目的就是把Task装饰的那个函数里边callback的参数用set_result()设置成返回值,保存在future里。哈哈 我觉得以后我看这里也不会看懂,还不如直接看代码容易。这里用到了带名字的元组,这个看到过没用过。set_result()用的地方很多 其他的基本就是异常处理, 先看看其他周边,想gen.Return是继承自Exception所以这个用raise,这个异常会在后边用的时候捕获到,然后当做结果。 其他的没看,代码没看全,没看到那些类和函数。 coroutine这个装饰器,内容很多。 先是执行函数,有返回值,保存,然后如果抛出Return exception 获取里边的值,或者其他程序异常。 没有异常,就判断结果是否是生成器,不是生成器直接将结果set_result保存到future并返回结果,如果是next执行之,如果执行完或者Return设置执行完的值,这里异常处理和上边一样,执行完后如果没有异常产生,执行Runner(),handler_yield没看,主要看了run(),处理方式基本相同,主要就是将刚刚执行的结果通过send方法返回给yield前边的变量,就是类似a = yield query()这种,将结果返回给a。 然后总结一下思路,可能不太对。requesthandler执行的时候,执行相对应的http method,如果返回的不是future,那ok,流程上边写过了,执行完没有异常并判断不是个生成器类型就会直接在future保存结果并返回。为什么还要保存到future中呢。因为requesthandler里的execute也是经过coroutine修饰过了。 发现返回一个future,因为比如一个get方法被我们用coroutine装饰了。然后他就yield,这个的返回结果就是你get方法的结果了。 然后执行对应的我的model里的search_result(),然后执行query语句,我都是用gen.Return返回的结果,怎么感觉这么复杂。。。感觉这样写不太对,不太符合设计 query方法先获取cursor,这些都是coroutine修饰的,都是返回的生成器类型。(之所以这样写,这个库只我自己用,我不喜欢callback的模式,感觉yield写起来也方便看起来也方便,封装的时候参数也不写callback了)使用gen.Task获取conn,为啥用这个因为这个必须设置callback,然后里边的callback参数就是conn,这样task会将装饰的函数参数callback的参数最终作为结果返回。这里说装饰也不太对,Task不是个装饰器。感觉跟functools里的partial很像,但不一样,他返回一个future。这样就会最终返回给我链接数据库的conn,在cursor我是用gen.Return返回corsors,这个会捕获到Return异常直接设置到future里当做结果,最后通过runner里的run返回给yield关键字前的cursor变量。这样就获取到了cousor。。。。。下边执行语句的时候和这个流程一样

Continue

看这个模块要先看with as的用法,最常用的方法就是打开一个文件: with open("filename") as f: f.read() with可以调用一个上下文管理器,产生运行时的上下文环境。上下文管理器主要定义两个方法,__enter__,__exit__。__enter__返回上下文里操作的对象,如f。__exit__是销毁对象和异常处理。 contextlib模块对外有三个接口, contextmanager装饰器,装饰的函数必须是一个生成器。然后返回一个函数,在函数调用的时候返回一个上下文管理器。 nested为了一次调用多个上下文管理器的时候用,将所有上下文管理器里的__enter__放到vars里,一次yield返回,然后unpack。就产生多个对象了。__exit__都放到exits列表里,在finally里统一调用,这些__exit__在调用上下文管理器产生异常时,如何处理。如果返回false,将会把异常继续抛出,返回true则不会抛出异常。 closing,这个用过,没想到的是竟然是个类,而不是个函数。就是把有close方法却没有__exit__方法的对象变成一个上下文管理器。代码很简单:

class closing(object):
    def __init__(self, thing):
        self.thing = thing
    def __enter__(self):
        return self.thing
    def __exit__(self, *exc_info):
        self.thing.close()

Continue

前边ioloop看完了,application以前也看过一点,现在看看application和IOLoop是怎么结合起来的。 Application里的listen(port),实例化一个HTTPServer(),然后listen port address。 HTTPServer()继承自TCPServer, httputil.HTTPServerConnectionDelegate。HTTPServer参数传入application实例,还有一些参数。app保存在属性request_callback中,调用TCPServer的初始化方法,ioloop默认为None。然后都是参数的 保存。 listen方法是TCPServer里的,第一个方法返回socket,后调用add_sockets。self.ioploop为None,调用类静态方法IOLoop.current(),实例化IOLoop。然后将所有socket保存到_sockets中,调用在netutil.py里的add_accept_handler。 add_accept_handler第二个参数是一个函数,_handle_connection,ssl的不看。总的说就是实例化一个IOStream,然后调用handle_stream,handle_stream应该是看HTTPServer里的定义,这里没有。我去 看到这里感觉又要晕了。httpserver.py里的handle_stream应该是启动了httpserver。看到这里总结一个下。 一条是add_accept_handler的第二个参数应该是启动httpserver的功能的一个函数,看参数名是个callback。实例化了一个IOStream还没看,然后调用handle_stream启动httpserver。 额,先看看IOStream。继承BaseIOStream,额,没啥看的,付了一堆的变量。然后看httpserver.py里的handle_stream,一个context,看HTTP1ServerConnection,主要看start_serving,先进行类型判断,这是返回true,因为HTTPServer继承自httputil.HTTPServerConnectionDelegate,类似接口,只定义了两个空方法。然后后边运行_server_request_loop,异步。主要调了连接的read_response方法。大体看了一下,就是对包内容进行解析了。不看了 没仔细看逻辑,感觉画个图会好一点,看的都快吐了。看个流程都这么麻烦,以后再静下心来看一遍。放松一下

Continue

看python社区大妈组织的内容里边有一篇讲python内存优化的,用到了__slots__。然后查了一下,总结一下。感觉非常有用 python类在进行实例化的时候,会有一个__dict__属性,里边有可用的实例属性名和值。声明__slots__后,实例就只会含有__slots__里有的属性名。

# coding: utf-8


class A(object):
    x = 1

    def __init__(self):
        self.y = 2

a = A()
print a.__dict__
print(a.x, a.y)
a.x = 10
a.y = 10
print(a.x, a.y)


class B(object):
    __slots__ = ('x', 'y')
    x = 1
    z = 2

    def __init__(self):
        self.y = 3
        # self.m = 5  # 这个是不成功的


b = B()
# print(b.__dict__)
print(b.x, b.z, b.y)
# b.x = 10
# b.z = 10
b.y = 10
print(b.y)


class C(object):
    __slots__ = ('x', 'z')
    x = 1

    def __setattr__(self, name, val):
        if name in C.__slots__:
            object.__setattr__(self, name, val)

    def __getattr__(self, name):
        return "Value of %s" % name


c = C()
print(c.__dict__)
print(c.x)
print(c.y)
# c.x = 10
c.z = 10
c.y = 10
print(c.z, c.y)
c.z = 100
print(c.z)
{'y': 2}
(1, 2)
(10, 10)
(1, 2, 3)
10
Value of __dict__
1
Value of y
(10, 'Value of y')
100

Continue

去官网下载了一个集成开发环境,直接安装。然后报错“Android Studio was unable to find a valid Jvm” google launchctl setenv STUDIO_JDK /Library/Java/JavaVirtualMachines/jdk1.8.0_25.jdk 解决之。 网上还有种方法是,finder --应用程序--android studio--显示包内容--contents--info.plist,搜索1.6.将1.6*改成1.6+就ok了。 Fetching android sdk component information,这个不知道具体干嘛的,好几次不成功。 同样的目录,contents/bin/idea.properties,最后加一行disable.android.first.run=true。 打开后的配置,configure--project Defaults--Project Structure--Android SDK location 添上 /Users/a0x55aa/Library/Android/sdk

Continue

tornado.ioloop.IOLoop.instance().start() ioloop继承自Configurable。 configurable_base返回IOLoop,然后调用configured_class,然后再看IOLoop的configurable_default。这里面根据不同系统选择了不同的IOLoop类实现返回。下一步是initialize初始化了。 看一下epoll吧。 先找了一下IOLoop的start(),意料之中。因为configurable_default返回的类实现都是别的类,要看具体别的类中的定义了。 epoll.py里的EPollIOLoop只定义了initialize,EPollIOLoop继承自PollIOLoop,在ioloop.py文件里。 PollIOLoop继承自IOLoop,现在还不知道为什么这么继承,先往下看。super,IOLoop里边是空的。下边用到initialize第二个参数是impl。在PollIOLoop里是select.epoll()。还要去看看platform/select.py,额 我去还是import select。标准库中的select.epoll()返回一个epoll obj。判断是否有fileno属性,这个方法是返回一个文件描述符的。然后不知道是怎么操作这个句柄的不懂。先过。。 设置了一堆值。看platform/common.py里的Waker.继承自interface.Waker.父类只是定义了几个方法名。 先看初始化,self.write是个socket.self.writer.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)注释说禁止buffer,有数据就立即发送。 下边是做了一个测试,好像有些系统不支持检查出来。 下边又没懂,a都关闭了,还要那个文件描述符干嘛.这块后边做个测试研究一下。 初始化完了回到PollIOLoop,add_handler,第一个参数a的文件描述符,第二个参数consume是从a读数据读完为止。第三个参数是IOLoop里定义的,这里体现出继承的意义来了。 看add_handler,spit_fd取文件描述符,第二个handlers空,添加fd为key,文件描述符,handler为值。 没看懂,注释说就为了在io loop空闲时,想让他醒来发送假数据,这里也先过,网络方面的还是懂的太少了 然后初始化完成了。。下边是调用instance()了。这个只有在IOLoop里有定义,这里才是真正的继承意义。开始是没有_instance的,然后加锁,定义个实例IOLoop()返回这个实例。 饶了这么多圈终于实例化了。。。卧槽来 然后start(),PollIOLoop里,这里开始ioloop的循环执行了。详细的先不看了,看了一下等后边仔细分析一下。上边的waker也是结合这里一起再看一遍。

Continue