樱桃好吃树难载,又到了樱桃下市的季节了。大连的大樱桃还是比较有名的,品种也很多,有红灯、美早、萨密豆、雷尼、8-102等10余个樱桃品种。
大连现在有不少樱桃自采园,喜欢自己动手丰衣足食的可以试试。
樱桃好吃树难载,又到了樱桃下市的季节了。大连的大樱桃还是比较有名的,品种也很多,有红灯、美早、萨密豆、雷尼、8-102等10余个樱桃品种。
大连现在有不少樱桃自采园,喜欢自己动手丰衣足食的可以试试。
在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++为中心更好,但你未必能接受。
星期天回到父母家,晚上吃饭的时候不知怎么父亲想起萌萌一个事,说她聪明”不好糊弄了“,说捡来的故事不相信了。
萌萌这时候接了一句”我是从妈妈肚子里生出来的“样子颇为认真,让我感觉非常有意思,于是想逗逗她。
”你不是妈妈肚子里生出来的,是从天上来的天使”。
萌萌开始很怀疑,“我就是妈妈肚子里生出来的”,于是我把故事说的比较像回事“你是从天上飞下来的,我和你妈妈把你的翅膀都保存起来了,放在银行里“。
萌萌开始围绕这个问题不停地问“那我安上翅膀会不会飞?能不能把翅膀让我看看?我不信我就是妈妈肚子里生出来的“诸如此类,小脸兴奋地通红。
说着说着,突然冒出一句”爸爸是从白菜叶子里出来的,爸爸是菜青虫!“把我们笑到不行。
宝贝,你就是我们的天使啊!
代码在这里:
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形式就好了。
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.