分类: tech

  • Lua编程、弱引用、招DotNet程序员

    Lua社区最近有很多值得关注的新闻,第一条毫无疑问是Lua5.2.0接近release,最新一版Lua 5.2.0 (beta-rc4)(http://www.lua.org/work),按照作者Luiz Henrique de Figueiredo的说法,大概还有一个多月时间就应该能看到release版本了。Lua5.2.0比较值得关注的是增加了一个关键字(goto),可以通过goto实现continue的功能,所以不出意料的依然没有continue,在twitter上云风回复说他统计了一下自己某个代码,里面好像也是continue远远少于goto的使用。另外还是要赞叹Lua作者的牛逼,现在Lua大概还是二十几个关键字,其它语言上百个关键字的伤不起啊!你都记不全!

    另一个新闻是LuaJit也接近release版,现在是2.0.0 Beta8,http://luajit.org/download.html 对于性能追求者来说,LuaJit是一个很好的选择,但是支持平台不够多(比如我的PowerPC啊)。最新一版对于ARM的支持是亮点,啥Android、iPhone的,统统都支持。另外FFI Library也是亮点,这个功能可以极大地提高对C API的开发支持。

    在新浪微博上(我的微博是http://weibo.com/sagasw )有人问我,学习Lua与C交互,什么项目比较好。下面是我的建议:

    1)主要用Lua,想用C作为模块支持某些特性。如果你想完成类似程序,那么Lua自己的module毫无疑问是最好的学习项目,比如5.2.0中的lbitlib.c、ldblib.c、lstrlib.c、ltablib.c,都是通过Lua API开发出来的。另外比如LuaSocket、LuaFileSystem都是很常用的模块,学学也都不错。

    2)主要用C,想用Lua作为动态支持。如果想达到这个目的,可以参考Programming In Lua(可以在网上免费阅读下载)中的示例。与1)也差不多,基本上都是通过Lua stack来与Lua访问。1)和2)基本上编程方式是共通的。

    另外可以参考这个项目http://labix.org/lunatic-python,可以实现Lua与Python互操作,类似项目还有http://pypi.python.org/pypi/lupa/0.17 

     

    Weak Reference是一个编程领域通用的概念,在http://en.wikipedia.org/wiki/Weak_reference 这里可以看到比较详细的介绍。DotNet中就有WeakReference这个概念,另外Lua有Weak Table概念。弱引用是指在有垃圾收集机制的程序语言中,常规情况下对某个对象的引用都是强引用,比如a=b,a就引用了b,如果b在其它地方不再被使用,但是a依然存在有效,那么b就仍然是可达的(reachable),或者用引用计数这方式来讲,就是reference count仍然大于0。但是这有一点问题,是我以前碰到过的。

    我在某个项目的性能改进中引入了cache机制,有一个全局的对象缓存管理器。我的实现很简单,就是用一个vector保存对象指针,在类析构函数中查找对象缓存管理器,决定是否真正释放对象,还是说仅仅把对象放到管理器中。

    由于代码写得不是很完美,其中有一个问题,就是指针在缓冲管理器中放着,但是实际对象实例已经被释放了。也就是说,为了真正释放对象实例,需要做两步才正确:第一步是查找缓存管理器,查找删掉里面的指针引用,第二步是真正释放对象。

    很麻烦是不是。对于C#这样的没有确定析构时间的编程语言来说,也有类似问题。我们举一个很典型的例子,如下图所示(from http://diditwith.net/2007/03/23/SolvingTheProblemWithEventsWeakEventHandlers.aspx):

    EventLeak

    可以看到当myForm释放,但是没有移除handler,那么handler指向就有问题。

    强引用的另外一个问题是会影响垃圾收集。比如我前面那个需要,如果把引用存放到某个全局对象管理器,那么GC会认为这个对象是可达的(reachable),没法正确的释放了。

    弱引用就是完成这个目的,一个弱引用对象,可以通过对Target是否为空来判断引用对象是否已经释放,而且不会影响垃圾收集有效性。实现方式(好像是)与我前面提到的也很类似,对象析构时,先从某个全局的弱引用队列中把相关Target删掉,然后再析构(所以弱引用是会影响一点点性能)。

     

    最近在找两个DotNet程序员,最好是有两三年开发经验,如果有WPF/SilverLight经验最好,要求DotNet知识牢固,对编程有兴趣,另外有较强的自学能力,英语能够进行基本对话交流。有意者请发简历到sagasw#gmail.com(替换#哦)。

  • 不同系统(C#/Python/IronPython/Jython/C++)之间的技术整合(续一)

    上一次讨论http://sunxiunan.com/?p=1854 发出去以后提问者回复了一些问题,然后也提出一些新问题,觉得这种总体设计还是挺有趣的,值得发出来一起看看。

        首先说明下为什么会有这样的想法吧—-公司里面有很多不同部门, 部门之间有不同的产品, 对于不同的产品和项目都有着自己的测试方案, 有手工的也有自动化的, 自动化的里面又有使用各种语言的(包括Tcl, Python, Lua等), 即使使用同一种语言, 也有使用各种框架的, 这样就导致了不同产品间很难沟通(最典型的案例就是需要互相借人的时候, 发现要重新学习一套测试方式, 周期太长), 同时也不便于管理. 于是呢, 领导们就突发奇想, 是不是可以统一一种语言和框架呢?为了能满足领导们以及测试部门等各方面的诉求,就有了以上的想法…..

        再来说说我的想法吧. 目前领导要统一已经是一个不可避免的问题了, 因此我非常希望可以引导到Python上面来(其实有些部门是使用Python的), 这里大概和我的个人喜好, 同时我也相信Python可以胜任这种情况. 于是为了证明这个, 所以我就有了以上的尝试. 所有的一切都是为了尽量少改动现有的代码而实现新的统一的目标,想调用Java的原因是有大量的类库目前可以使用,希望调用C/C++的原因是因为其他部门非常有可能需要与硬件相关的C/C++的扩展来实现框架,要尽量满足大家的需求大家才会支持你 。。。。。。

        至于框架方面,说实话,现在Python的测试框架好像还没有特别成熟的,相对来说见得多的是Robot Framework,不过其实我自己的构想是重新创建的一个可以将各个部门完全分离同时又可以分别集群的架构,不过这些都是后话了。

    至于这位仁兄说的这条:

    3)IronPython无法调用C扩展,但是很容易调用C#,可以考虑将其作为C#与CPython的包装层,仅此而已,不要用的太多。
    4)Jython也是一样,仅用于Java与CPython的包装。

    鉴于我才疏学浅,不大理解具体怎么做,因为我的理解是Jython和IronPython都是重新实现的解释器,如何去包装CPython呢?(类似Pyhon For .net的做法?如果是这样的话,这个难度还是相当大的。。。。)

    希望能进一步解释。

    ============================

    我的回答如下:

    包装层(wrapper)是一个抽象概念,有句名言说:编程问题大多数可以通过引入新的抽象来解决(当然,同时也产生新的问题)。

    我们以IronPython和CPython以及现有的C# DotNet程序、C++程序为例来做个探讨好了。在上一次讨论提问者描述以后,我的感觉就是他对性能要求不高,交互紧密性要求不高(也就是未必有IronPython必须不得不直接调用C编写的Python扩展要求),只要把异构系统整合起来能够互相通讯就好。

    整合异构系统,需要分清主次,我这里的设计方案,是以CPython为主,其它编程语言的应用程序或者以DLL形式存在或者被CPython程序调用激活,或者是驻留系统中等待CPython主程序的消息。如果你的方案不是这样,建议你重新考虑一下,没有主次之分的系统设计是有问题的。

    另外看这位提问者的描述,他对于系统之间传递的内容,以及交互的紧密程度,要求不是很高,甚至感觉上就是只要Python能调用一下这些系统就行了。

    这也是设计者需要考虑的,真正需要整合起来做什么,把方案做得细致一些,多考虑一些。

     

    类似这种不同语言的系统进行通讯,基本上有这样几个办法:

    1,基于消息Message Queue通讯

    定义通用格式消息或者使用通用现成格式(比如ProtocolBuffer、Thrift、Json、XML、MsgPack等等),使用跨开发平台通讯方式比如zeromq、http web service进行通讯支持。这是扩展性最好、实现也不麻烦的解决方案,在Python-cn中Zoom.Quiet也提出同一种方案。

    http://en.wikipedia.org/wiki/%C3%98MQ

    http://nichol.as/zeromq-an-introduction

    关于数据序列化比较,可以参考这里

    http://en.wikipedia.org/wiki/Comparison_of_data_serialization_formats

    另外在Windows下,如果是本机,也可以通过Windows自定义消息在不同系统之间传递。

    Python、IronPython也好,C#也好,或者是C++、Lua、Java,它们都很容易建立Web Server,这种方案可以优先考虑。而且scalablity比较好,容易扩展。

     

    2,基于COM

    这个对开发者要求比较高,另外只能用于IronPython和Python以及C++之间,不能用于Jython和Java。但是如果不需要考虑Java系产品,可以考虑COM,其实COM技术即使在DotNet发展到4.0的现在,依然有强大的生命力。而且开发其实也不难。

     

    3,基于数据库或文件系统传递

    这种方案也是比较通用的,如果你不需要序列化对象,只关心结果(比如数字、字符串、时间等等),这个方案也可以参考。优点是相比第一种,更容易学习使用。可以使用SQLite这样轻量的数据库。

     

    4,基于Python序列化传递对象

    这是针对Python编程语言特定的办法。同时也回答了这个问题:怎么叫用IronPython作CPython和C#之间的包装器?

    如果了解Python,应该知道Python有个序列化方法pickle,可以把对象保存到文件中,以后载入。

    幸运的是,经过我的实验,IronPython2.7支持pickle,与CPython之间通过pickle文件传递对象,那是非常容易。

    也就是说,C#程序运行完毕,或者通过IronPython运行完毕,可以将结果保存到pickle文件中,CPython载入以后继续运行,装得跟直接一样。

    通过我的描述可以看出,IronPython和CPython还是没关联,你是你我是我。这的确没办法,因为它们各自都是完整的系统,设计初衷也没考虑到直接交互,但是IronPython发展前景不错,值得跟进。相比Python.Net而言,我还是建议使用CPython和IronPython。

    iron_cpython

     

    最后要说的是,这种大一统的方案,如果没有强力领导介入和长期支持,基本上不能成功。但这不是技术方案需要考量的。

  • 不同系统(C#/Python/IronPython/Jython/C++)之间的技术整合

    在python-cn讨论组看到某人咨询架构设计,心痒回复了一下,有点价值。放在这里大家共享一下。

    Python的解释器可谓相当的丰富了,CPython,Jython,IronPython,他们分别可以以非常简单的方式与C,Java以及.NET调用, 但是它们也有严重的缺点—-他们都是单独的解释器,因此想把他们共同使用就比较麻烦了.

        最近工作上遇到这样的场景, 现有的代码中大部分代码是使用C#写的,考虑到性能以及工作量的问题, 这部分代码必须可以用上; 由于别人提供的工具中, 有大量Jython的代码, 这部分代码也不可能重写; 后续代码可能涉及到部分硬件相关代码,可能需要使用C/C++进行扩展编写; 最后后续的代码希望使用Python, 以保证开发的效率以及灵活性.  这样就遇到难题了, 如何保证这些不同语言编写的代码在同一个工程中使用呢?

        我也做了一些尝试,但是结果都不是非常理想:

            CPython: 1,使用C/C++标准扩展的方式重新将C#编写的.NET组件包装之后, 编译可以通过, 但是实际调用的时候会显示找不到目标, 使用ctypes调用用C/C++包装之后的.NET组件,报Windows Error错误, 网上随便搜索了下, CPython想使用.NET组件是个非常复杂的问题; (其实在这里我并不是非常理解C#编译成为DLL之后调用过程是怎么样的, 因为理论上C#也是一个解释型的语言, 他的执行过程是不是需要什么依赖呢? 在这里我做的实验是非常简单:使用C#实现一个类,里面有一个static method, 在C/C++的文件中调用C#中实现的static method编译为PYD文件给Python调用—-也许是我的调用逻辑有问题)

            2,同时CPython想使用Java代码比较繁琐. 

            Jython: 不支持ctypes, 使用C/C++代码相对繁琐, 与.NET组件的调用也比较繁琐, 同时Python的支持版本很低, 貌似开发进度比较不给力啊…..

            IronPython: C/C++标准扩展无法在IronPython中调用, 调用Java也相对比较繁琐.

        另外我还考虑过通过COM使用CPython调用.NET组件, 应该可行但是不想使用….

        也想过通过把不同的语言实现的部分分离在不同的进程中通讯也是可行的, 但是带来的性能问题以及稳定性难以评估.

    由于时间比较仓促,需要尽快作一个技术上的选型, 所以没有更多的时间来做更多的实验, 所以在这里询问下, 不知道这里有没有以前遇到过类似问题,或者对这些有所了解的朋友, 还请不吝赐教!谢谢!

    ==================================

    我的回答如下:

     

    这个架构设计蛮有意思的,首先想问几个问题确定一下细节:

    1)Python选型是否是官方意见?已经决定好的?还是仅仅是你个人的?
    2)不同语言模块交换的工作是一次性的(就是用完就抛的)?还是说需要长期使用的?
    3)这里需要重用的是数据?还是业务逻辑?还是仅仅就是模块?
    4)你对整体设计是否有决定权?你对这些系统(Jython、CPython、C++、C#)是否了解?
    5)当时做出这些选型是否考虑过整合?

    说实话,从你的问题来看,你对整个系统了解程度还是不够的,这是设计的大忌。

    建议你按照这些步骤来做:

    1)确定真正的问题列表。把不同模块画出来,那些需要交换数据,那些需要重用逻辑。把不同系统之间的交互(已有的和将来要有的)列成表格,加上估计的技术难度以及估计的工作时间。
    先把思路搞清晰,要把系统的真正问题了解透,这点最为重要。
    再重复强调一次,编程是为了解决问题,重中之重就是确定你解决的是真正问题而不是枝节。

    2)按照问题优先级,来进行技术分析。比如C#与Python的交互,需要Python调用C#的逻辑。最佳方案是C#暴露为service形式,可以通过web service(WCF)很容易实现,数据格式可以为xml或者json,都是语言无关的。
    也可以C#作为COM组件形式暴露,优点是可重用性更好,C++也可以直接使用。

    3)IronPython无法调用C扩展,但是很容易调用C#,可以考虑将其作为C#与CPython的包装层,仅此而已,不要用的太多。

    4)Jython也是一样,仅用于Java与CPython的包装。

    5)CPython与硬件可以通过C编写扩展来实现,不是很难。我最近在翻译的一本书就是有类似整合方法。

    这里的设计方案是以CPython作为中心,其它方案向CPython靠拢。当然我觉得以C++为中心更好,但你未必能接受。

  • C#研究系列-List<>与ArrayList的几个研究心得及问题(下)

    代码在这里:

    https://gist.github.com/921385

    与(上)一样在一开始定义了两个继承List与ArrayList的空类。
    // public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable

    class CFromList : List<int> { }

    // public class ArrayList : IList, ICollection, IEnumerable, ICloneable

    class CFromArrayList : ArrayList{ }

    注意在87行,我注释了这行代码

    // list1[index++] = a;

    意思很简单,就是要修改iterate当前位置的值。
    其实我当初写下这个代码也就是随手为之,因为这种行为在C++中不算啥(只是对值进行修改,并不会修改list本身内存排列)。
    可是debug的时候,蹦出异常InvalidOperationException了。太奇怪了。
    好在我设置了step into CLR code,所以能跟踪到List内部的一些实现。从73到85行就是我找到的一些内容。
    在List.cs代码中,前面list1[index++]=a;的赋值语句会进入这个函数public T this[int index] set{},在这个属性函数中
    _items[index] = value; _version++;
    所以_version会增加1。在MoveNext函数中,会检查这个_version
    private bool MoveNextRare() {

    if (version != list._version) {

    ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);

    }

    index = list._size + 1;

    current = default(T);

    return false;

    }

    很显然,赋值以后,version和list._version不一样了。如果我们用try catch包围这些代码,那么就会捕获这个异常。

    另外一个问题来了,为何ArrayList没有异常呢?在我debug的时候,如果有list2[index++]=a;这样的修改,代码就挂在这块了,也没有异常弹出。

    加上try catch以后就没有问题了,这个就更奇怪了。

    从MSDN可以看到,List在foreach这种形式的循环下是不可以修改内容。必须说,这个规定太蛋疼了。如果想修改也很容易,不用这种iterator形式就好了。

  • Re 浅谈C和C++中的const关键字

    This article contains many errors, I just list them simply.
    http://www.cnblogs.com/dolphin0520/archive/2011/04/18/2020248.html

    BTW About const concept in C/C++, I have 2 articles.
    《c专家编程》阅读笔记-关于const指针 http://sunxiunan.com/?p=1161
    技术笔记-关于c/c++中的const http://sunxiunan.com/?p=870

    ————————
    “但是程序中使用过多的const,可能在对代码的阅读时增加一定的难度”
    Can’t understand. This idea is so strange.
    If possible, you should use const as possible. It is a good contract.

    ————————
    const int n; 这种声明方式是错误的
    This definition method is wrong. (should NOT declaration!)
    extern char* const p; // this is declaration, p as extern variable

    ————————
    指针常量:即指针本身的值是不可改变的,而指针指向的变量的值是可以改变的;
    I never heard the concept “指针常量”, it should be “the pointer points to constant” 指针指向常量!!

    ————————
    “C语言和C++中的const有很大区别。在C语言中用const修饰的变量仍然是一个变量;而在C++中用const修饰过后,就变成常量了。
    const int a=3; int *pa=&a; *pa=4; printf(“%d\n”,*pa); printf(“%d\n”,a);
    这种情况在C++中是不允许的,原因在于a用const修饰后,已经成为常量了,因此是不允许被修改的,无论是显示的更改a的值或是通过其它方法修改它的值都是不允许的。”

    !!!! WTF !!
    C++ has a keyword const_cast !!

    Try following code:
    const int a=3;
    int *pa= const_cast < int * > (&a); *pa=4;
    printf(“%d\n”,*pa);
    printf(“%d\n”,a);

    Will print out “4 4” as result.