iceKing

iceKing 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 该用户太懒什么也没留下

个人动态

iceKing 报名了系列讲座 · 11月5日

iceKing 报名了系列讲座 · 11月5日

iceKing 提出了问题 · 10月17日

需要对性别这个字段加索引的场景。

面试时,关于 MySQL 的索引使用问题,我说对于性别这种区分度不高的字段,不需要加索引,被追问有没有需要对性别加索引的场景,我没想到。各位有没有想法?

关注 1 回答 1

iceKing 赞了回答 · 7月23日

解决vscode 中 C 语言配置问题,includePath 没起作用。

你应该给gcc传递包含路径,为.vscode/tasks.json添加以下参数:

{
    "tasks": [
        {
            "args": [
                //...
                "-I${fileDirname}/include",
            ],
            //...
         }
}

或者,把tasks里的command项改成"make",其他无关项删除,然后自己写makefile来生成。

关注 3 回答 3

iceKing 赞了回答 · 7月23日

解决vscode 中 C 语言配置问题,includePath 没起作用。

gcc stack.c -o stack

这和 vsc 没关系,那个路径是给 vsc 插件使用的,目的是找到“正确”的 .h 文件,做语法解析

然而你是的错误是 gcc 编译错误,该使用 gcc 的 -I 参数指定头文件搜索路径

gcc stack.c -o stack -I ./include

关注 3 回答 3

iceKing 赞了文章 · 7月17日

Python开启尾递归优化!

Python尾递归优化

一般递归与尾递归

一般递归:

def normal_recursion(n):
    if n == 1:
        return 1
    else:
        return n + normal_recursion(n-1)

执行:

normal_recursion(5)
5 + normal_recursion(4)
5 + 4 + normal_recursion(3)
5 + 4 + 3 + normal_recursion(2)
5 + 4 + 3 + 2 + normal_recursion(1)
5 + 4 + 3 + 3
5 + 4 + 6
5 + 10
15

可以看到, 一般递归, 每一级递归都产生了新的局部变量, 必须创建新的调用栈, 随着递归深度的增加, 创建的栈越来越多, 造成爆栈?

尾递归

尾递归基于函数的尾调用, 每一级调用直接返回递归函数更新调用栈, 没有新局部变量的产生, 类似迭代的实现:

def tail_recursion(n, total=0):
    if n == 0:
        return total
    else:
        return tail_recursion(n-1, total+n)

执行:

tail_recursion(5, 0)
tail_recursion(4, 5)
tail_recursion(3, 9)
tail_recursion(2, 12)
tail_recursion(1, 14)
tail_recursion(0, 15)
15

可以看到, 尾递归每一级递归函数的调用变成"线性"的形式. 这时, 我们可以思考, 虽然尾递归调用也会创建新的栈, 但是我们可以优化使得尾递归的每一级调用共用一个栈!, 如此便可解决爆栈和递归深度限制的问题!

C中尾递归的优化

gcc使用-O2参数开启尾递归优化:

int tail_recursion(int n, int total) {
    if (n == 0) {
        return total;
    }
    else {
        return tail_recursion(n-1, total+n);
    }
}

int main(void) {
    int total = 0, n = 4;
    tail_recursion(n, total);
    return 0;
}

反汇编

$ gcc -S tail_recursion.c -o normal_recursion.S
$ gcc -S -O2 tail_recursion.c -o tail_recursion.S gcc开启尾递归优化

对比反汇编代码如下(AT&T语法, 左图为优化后)

优化

可以看到, 开启尾递归优化前, 使用call调用函数, 创建了新的调用栈(LBB0_3); 而开启尾递归优化后, 就没有新的调用栈生成了, 而是直接pop bp指向的_tail_recursion函数的地址(pushq %rbp)然后返回, 仍旧用的是同一个调用栈!

Python开启尾递归优化

cpython本身不支持尾递归优化, 但是一个牛人想出的解决办法:实现一个 tail_call_optimized 装饰器

#!/usr/bin/env python2.4
# This program shows off a python decorator(
# which implements tail call optimization. It
# does this by throwing an exception if it is
# it's own grandparent, and catching such
# exceptions to recall the stack.

import sys

class TailRecurseException:
    def __init__(self, args, kwargs):
        self.args = args
        self.kwargs = kwargs

def tail_call_optimized(g):
    """
    This function decorates a function with tail call
    optimization. It does this by throwing an exception
    if it is it's own grandparent, and catching such
    exceptions to fake the tail call optimization.

    This function fails if the decorated
    function recurses in a non-tail context.
    """
    def func(*args, **kwargs):
        f = sys._getframe()
        if f.f_back and f.f_back.f_back \
            and f.f_back.f_back.f_code == f.f_code:
            # 抛出异常
            raise TailRecurseException(args, kwargs)
        else:
            while 1:
                try:
                    return g(*args, **kwargs)
                except TailRecurseException, e:
                    args = e.args
                    kwargs = e.kwargs
    func.__doc__ = g.__doc__
    return func

@tail_call_optimized
def factorial(n, acc=1):
    "calculate a factorial"
    if n == 0:
        return acc
    return factorial(n-1, n*acc)

print factorial(10000) 

这里解释一下sys._getframe()函数:

sys._getframe([depth]):
Return a frame object from the call stack.
If optional integer depth is given, return the frame object that many calls below the top of the stack.
If that is deeper than the call stack, ValueEfror is raised. The default for depth is zero,
returning the frame at the top of the call stack.

即返回depth深度调用的栈帧对象.

import sys

def get_cur_info():
    print sys._getframe().f_code.co_filename  # 当前文件名
    print sys._getframe().f_code.co_name  # 当前函数名
    print sys._getframe().f_lineno # 当前行号
    print sys._getframe().f_back # 调用者的帧

更多关于sys._getframe的使用请看Frame Hacks
说一下tail_call_optimized实现尾递归优化的原理: 当递归函数被该装饰器修饰后, 递归调用在装饰器while循环内部进行, 每当产生新的递归调用栈帧时: f.f_back.f_back.f_code == f.f_code:, 就捕获当前尾调用函数的参数, 并抛出异常, 从而销毁递归栈并使用捕获的参数手动调用递归函数. 所以递归的过程中始终只存在一个栈帧对象, 达到优化的目的.
为了更清晰的展示开启尾递归优化前、后调用栈的变化和tail_call_optimized装饰器抛异常退出递归调用栈的作用, 我这里利用pudb调试工具做了动图:

开启尾递归优化前的调用栈

开启尾递归优化后(tail_call_optimized装饰器)的调用栈

通过pudb右边栏的stack, 可以很清晰的看到调用栈的变化.
因为实现了尾递归优化, 所以factorial(10000)都不害怕递归深度限制报错啦!

查看原文

赞 12 收藏 17 评论 2

iceKing 提出了问题 · 7月15日

解决vscode 中 C 语言配置问题,includePath 没起作用。

文件目录结构

只为了测试将 .h 单独放在一个文件夹中。

image.png

stack.c

// ...
#include "stack.h"
//...

c_cpp_properties.json

${workspaceFolder}/include/** 试图将工作目录下的 include 文件夹包含进去,但未生效。

{
    "configurations": [
        {
            "name": "Mac",
            "includePath": [
                "${workspaceFolder}/**",
                "${workspaceFolder}/include/**"
            ],
            "defines": [],
            "macFrameworkPath": [
                "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks"
            ],
            "compilerPath": "/usr/bin/gcc",
            "cStandard": "c11",
            "cppStandard": "c++17",
            "intelliSenseMode": "gcc-x64"
        }
    ],
    "version": 4
}

运行报错

mypc$ gcc stack.c -o stack
stack.c:5:10: fatal error: 'stack.h' file not found
#include "stack.h"
         ^~~~~~~~~
1 error generated.

请有经验的同学多多指教,谢谢!

关注 3 回答 3

iceKing 评论了文章 · 2019-02-28

vscode+sftp 开发模式环境的同步

背景

项目用到连接远程测试服务器进行开发联调;需要借用FTP/SFTP工具;在strom编辑器能够快速的配置起来;但是在vscode下;需要安装SFTP/FTP的扩展插件才能同步代码

实现

首先vscode中安装插件sftp;作者是liximomo;安装完以后重新加载一下;然后去配置同步数据的参数;此时注意这个配置文件需要自己手动的创建(我按照作者的use方式没有成功)目录地址为 .vscode 在该目录下新建一个sftp.json;然后具体的配置选项我贴上我的配置选项;你可以参考改为自己的

{
    "host": "ip地址",
    "port": 22,
    "username": "登录名",
    "password": "登录密码",
    "protocol": "sftp", 
    "agent": null,
    "privateKeyPath": null, 
    "passphrase": null, 
    "passive": false, 
    "interactiveAuth": true,
    "remotePath": "需要打到的远程的文件夹地址",
    "uploadOnSave": true,
    "syncMode": "update",
    "ignore": [
        "**/.vscode/**",
        "**/.git/**",
        "**/.DS_Store"
    ],
    "watcher": {
        "files": "glob",
        "autoUpload": true,
        "autoDelete": true
    }

}

这样也要注意;我在代码里面没有写配置项的注释;因为在我本机如果出现 // 这样的注释符都会报错;也不能成功同步代码;至于每一项的配置;可以查看作者的github的内容 https://github.com/liximomo/v... (我就是复制了了里面的全部;一直报错 - -!这坑真大);等都编辑完成保存后;可以编辑保存一下;然后右键Upload;刷新一下浏览器查看是否同步了代码。
如果发现已经可以了;就证明已经成功了;不妨给Upload编辑一个快捷键(我自己编辑的 ctrl+alt+s ;和保存多了一个alt)

将配置改为"uploadOnSave": true,就可以实现保存自动提交了;不需要设置快捷键了

最后

不想放弃vscode这个编辑器;主要是站30MB的运行内存很吸引人(没钱换mac);社区也很活跃插件层出不穷;自己搜度娘也一直不能同步代码;可能还是自己配置的有问题吧;写这个文章是想把这个方式分享出去;有像我这样的开发模式的同学的时候也能快速的配置完ftp同步开发

如果你发现配置了没有效果;留言大家一起解决

查看原文

iceKing 提出了问题 · 2018-05-02

怎么使用tinyMCE中的样式,使提交后的代码高亮?

使用Flask做的博客,加了个tinyMCE文本编辑器,在编辑界面上,代码是可以高亮的:

clipboard.png

提交后,由于不知道怎样关联到tinyMCE中相应的样式,代码自然无法高亮:

clipboard.png
我想仍使用tinyMCE提供的样式来渲染提交后的页面,这样保证提交前后的显示是一样的。没找到相关配置。前端渣,轻喷。求助,请问该怎样解决呢?

关注 2 回答 2

iceKing 赞了回答 · 2018-05-02

解决线程池+队列(ThreadPoolExecutor+queue)的这段程序怎样终止?

因为两个线程里一直在while True,可以增加一个结束信号,例如给队列里发送一个-1,线程接受到的话退出while循环,要注意两个队列都要发送结束信号。

关注 2 回答 1

认证与成就

  • 获得 3 次点赞
  • 获得 9 枚徽章 获得 0 枚金徽章, 获得 1 枚银徽章, 获得 8 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2017-11-18
个人主页被 138 人浏览