天天好味道

没钱没权没户口,靠走靠吼靠小狗
随笔 - 90, 文章 - 1, 评论 - 557, 引用 - 5

导航

<2009年7月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

公告

系分系分

留言簿(15)

随笔分类

随笔档案

文章档案

相册

我的链接

搜索

最新评论

阅读排行榜

评论排行榜

一段Python程序和C程序的对比

VCKbase的论坛上有人提了一个问题:
遇到的问题是,我把E-mail地址收集在txt文件中(每行一个E-mail地址,共78000行),要求是把其中重复的E-mail地址全部去掉。考虑编程方便,我用了CString类,但似乎效率不高。我写出来的整理78000份E-mail地址的需要近7分钟的时间

我给他用Python实现了一个(这个版本是修改过的,当时我随手实现的一个版本做错了,呵呵)
这里算法的主要内容就是利用hash_table来判断email是否已经重复出现,这比字符串的查找要快的多。

#remove duplicated email address from file
import datetime
if __name__ == "__main__":
 t = datetime.datetime(2000,1,1)
 print str(t.today())
 hashtable = {}
 f = file("email.txt","r")
 f2 = file("email_new.txt","w")
 line = f.readline();
 while len(line)>0:
  if not hashtable.has_key(line): 
   hashtable[line] = 1
   f2.write(line)
  line = f.readline();
 f.close()
 f2.close()
 t2 = datetime.datetime(2000,1,1)
 print str(t2.today())
  
上面的算法在我的机器上:P4 2.8G,512M 内存,耗时大约300ms,跟他的7分钟差了天了。而我当时错误的算法,需要2分半钟,所以我贴到我们内部的BBS上,我的一个同学实现了如下算法(C):
#include 
#include 
#include 
#include "list.h"
#define HASH_SIZE 262157
#define LINE_MAX_LEN 1024
struct list_node {
 struct list_head head;
 int len;
 char *str;
};
struct list_head hash_table[HASH_SIZE];
static inline int
hash_string (const char *ptr, int len)
{
 unsigned int hash = 0;
 
 for (hash = 0; len; len--, ptr++) {
  /* (31 * hash) will probably be optimized to ((hash << 5) - hash). */
  hash = 31 * hash + *ptr;
 }
 
 return (hash % HASH_SIZE);
}
static inline int
cmpfn(const struct list_node *node, int len, char *str)
{
 return ((node->len == len) && (memcmp(node->str, str, len) == 0));
}
int main(int argc, char **argv)
{
 int i, hash, len;
 struct list_node *node;
 char buf[LINE_MAX_LEN];
 FILE *fp_in, *fp_out;
 
 if(argc != 3) {
  printf("error: \nplease use eml as:\n eml infile outfile\n");
  return -1;
 }
 fp_in = fopen(argv[1], "r");
 if(!fp_in) {
  printf("error: could not open infile %s\n", argv[1]);
  return -1;
 }
 fp_out = fopen(argv[2], "w");
 if(!fp_out) {
  printf("error: could not open infile %s\n", argv[2]);
  return -1;
 }
 for(i=0; istr = (char *)malloc(len + 1);
   node->len = len;
   memcpy(node->str, buf, len);
   node->str[len] = '\0';
   list_append(&(hash_table[hash]), node);
  }
 }
 return 0;
}
还有.h文件:

#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H
extern inline void prefetch(const void *x)
{
 return;
}
/*
 * Simple doubly linked list implementation.
 *
 * Some of the internal functions ("__xxx") are useful when
 * manipulating whole lists rather than single entries, as
 * sometimes we already know the next/prev entries and we can
 * generate better code by using them directly rather than
 * using the generic single-entry routines.
 */
struct list_head {
 struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
 struct list_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do { \
 (ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
/*
 * Insert a new entry between two known consecutive entries. 
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
static inline void
__list_add(struct list_head *new,
    struct list_head *prev, struct list_head *next)
{
 next->prev = new;
 new->next = next;
 new->prev = prev;
 prev->next = new;
}
/**
 * list_add - add a new entry
 * @new: new entry to be added
 * @head: list head to add it after
 *
 * Insert a new entry after the specified head.
 * This is good for implementing stacks.
 */
static inline void
list_add(struct list_head *new, struct list_head *head)
{
 __list_add(new, head, head->next);
}
/**
 * list_add_tail - add a new entry
 * @new: new entry to be added
 * @head: list head to add it before
 *
 * Insert a new entry before the specified head.
 * This is useful for implementing queues.
 */
static inline void
list_add_tail(struct list_head *new, struct list_head *head)
{
 __list_add(new, head->prev, head);
}
/*
 * Delete a list entry by making the prev/next entries
 * point to each other.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
static inline void
__list_del(struct list_head *prev, struct list_head *next)
{
 next->prev = prev;
 prev->next = next;
}
/**
 * list_del - deletes entry from list.
 * @entry: the element to delete from the list.
 * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
 */
static inline void
list_del(struct list_head *entry)
{
 __list_del(entry->prev, entry->next);
 entry->next = (void *) 0;
 entry->prev = (void *) 0;
}
/**
 * list_del_init - deletes entry from list and reinitialize it.
 * @entry: the element to delete from the list.
 */
static inline void
list_del_init(struct list_head *entry)
{
 __list_del(entry->prev, entry->next);
 INIT_LIST_HEAD(entry);
}
/**
 * list_move - delete from one list and add as another's head
 * @list: the entry to move
 * @head: the head that will precede our entry
 */
static inline void
list_move(struct list_head *list, struct list_head *head)
{
 __list_del(list->prev, list->next);
 list_add(list, head);
}
/**
 * list_move_tail - delete from one list and add as another's tail
 * @list: the entry to move
 * @head: the head that will follow our entry
 */
static inline void
list_move_tail(struct list_head *list, struct list_head *head)
{
 __list_del(list->prev, list->next);
 list_add_tail(list, head);
}
/**
 * list_empty - tests whether a list is empty
 * @head: the list to test.
 */
static inline int
list_empty(struct list_head *head)
{
 return head->next == head;
}
static inline void
__list_splice(struct list_head *list, struct list_head *head)
{
 struct list_head *first = list->next;
 struct list_head *last = list->prev;
 struct list_head *at = head->next;
 first->prev = head;
 head->next = first;
 last->next = at;
 at->prev = last;
}
/**
 * list_splice - join two lists
 * @list: the new list to add.
 * @head: the place to add it in the first list.
 */
static inline void
list_splice(struct list_head *list, struct list_head *head)
{
 if (!list_empty(list))
  __list_splice(list, head);
}
/**
 * list_splice_init - join two lists and reinitialise the emptied list.
 * @list: the new list to add.
 * @head: the place to add it in the first list.
 *
 * The list at @list is reinitialised
 */
static inline void
list_splice_init(struct list_head *list, struct list_head *head)
{
 if (!list_empty(list)) {
  __list_splice(list, head);
  INIT_LIST_HEAD(list);
 }
}
/**
 * list_entry - get the struct for this entry
 * @ptr: the &struct list_head pointer.
 * @type: the type of the struct this is embedded in.
 * @member: the name of the list_struct within the struct.
 */
#define list_entry(ptr, type, member) \
 ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
/**
 * list_for_each - iterate over a list
 * @pos: the &struct list_head to use as a loop counter.
 * @head: the head for your list.
 */
#define list_for_each(pos, head) \
 for (pos = (head)->next, prefetch(pos->next); pos != (head); \
         pos = pos->next, prefetch(pos->next))
/**
 * list_for_each_safe - iterate over a list safe against removal of list entry
 * @pos: the &struct list_head to use as a loop counter.
 * @n:  another &struct list_head to use as temporary storage
 * @head: the head for your list.
 */
#define list_for_each_safe(pos, n, head) \
 for (pos = (head)->next, n = pos->next; pos != (head); \
  pos = n, n = pos->next)
/**
 * list_for_each_entry - iterate over list of given type
 * @pos: the type * to use as a loop counter.
 * @head: the head for your list.
 * @member: the name of the list_struct within the struct.
 */
#define list_for_each_entry(pos, head, member)    \
 for (pos = list_entry((head)->next, typeof(*pos), member), \
       prefetch(pos->member.next);   \
      &pos->member != (head);      \
      pos = list_entry(pos->member.next, typeof(*pos), member), \
       prefetch(pos->member.next))
/*this is the begin of listhelp ;-)*/
#define LIST_FIND(head, cmpfn, type, args...)  \
({       \
 const struct list_head *__i = (head);  \
       \
 do {      \
  __i = __i->next;   \
  if (__i == (head)) {   \
   __i = NULL;   \
   break;    \
  }     \
 } while (!cmpfn((const type)__i , ## args)); \
 (type)__i;     \
})
#define LIST_FIND_W(head, cmpfn, type, args...) \
({      \
 const struct list_head *__i = (head); \
      \
 do {     \
  __i = __i->next;  \
  if (__i == (head)) {  \
   __i = NULL;  \
   break;   \
  }    \
 } while (!cmpfn((type)__i , ## args)); \
 (type)__i;    \
})
static inline int
__list_cmp_same(const void *p1, const void *p2)
{
 return p1 == p2;
}
/* Is this entry in the list? */
static inline int
list_inlist(struct list_head *head, const void *entry)
{
 return LIST_FIND(head, __list_cmp_same, void *, entry) !=NULL;
}
/* Delete from list. */
#ifdef CONFIG_NETFILTER_DEBUG
#define LIST_DELETE(head, oldentry)     \
do {         \
 if (!list_inlist(head, oldentry))    \
  printk("LIST_DELETE: %s:%u `%s'(%p) not in %s.\n", \
         __FILE__, __LINE__, #oldentry, oldentry, #head); \
        else list_del((struct list_head *)oldentry);   \
} while(0)
#else
#define LIST_DELETE(head, oldentry) list_del((struct list_head *)oldentry)
#endif
/* Append. */
static inline void
list_append(struct list_head *head, void *new)
{
 list_add((new), (head)->prev);
}
/* Prepend. */
static inline void
list_prepend(struct list_head *head, void *new)
{
 list_add(new, head);
}
/* Insert according to ordering function; insert before first true. */
#define LIST_INSERT(head, new, cmpfn)    \
do {        \
 struct list_head *__i;     \
 for (__i = (head)->next;    \
      !cmpfn((new), (typeof (new))__i) && __i != (head); \
      __i = __i->next);     \
 list_add((struct list_head *)(new), __i->prev);  \
} while(0)
/* If the field after the list_head is a nul-terminated string, you
   can use these functions. */
static inline int
__list_cmp_name(const void *i, const char *name)
{
 return strcmp(name, i + sizeof (struct list_head)) == 0;
}
static inline int
__list_cmp_nameptr(const void *i, const char *name)
{
 return strcmp(name, ((char *)
        *(unsigned long *) (i +
       sizeof (struct list_head)))) ==
     0;
}
/* Returns false if same name already in list, otherwise does insert. */
static inline int
list_named_insert(struct list_head *head, void *new)
{
 if (LIST_FIND(head, __list_cmp_name, void *,
        new + sizeof (struct list_head)))
   return 0;
 list_prepend(head, new);
 return 1;
}
static inline int
list_nameptr_insert(struct list_head *head, void *new)
{
 if (LIST_FIND(head, __list_cmp_nameptr, void *,
        new + sizeof (struct list_head)))
   return 0;
 list_prepend(head, new);
 return 1;
}
/* Find this named element in the list. */
#define list_named_find(head, name)   \
LIST_FIND(head, __list_cmp_name, void *, name)
#define list_nameptr_find(head, name)   \
LIST_FIND(head, __list_cmp_nameptr, void *, name)
#endif
在我的机器上测试(cygwin):耗时竟然是400ms!
当然,这里包含了Cygwin的间接调用开销。

很难想象吧,Python在这里的性能竟然跟C不相上下!而且Python的代码比C不知道短了多少倍!
所以讲,Python是蛮好用的,:-).
不过,这个例子其实是个特殊情况,以前我们玩过的另外一个程序,C的性能就比Python快得多。不过代码量还是Python简短得多。有兴趣的朋友可以用自己熟悉的语言来测试一下,下面是测试文件(也是我用11行python代码产生的,有1/10的email是重复的):
这其实是一个rar,下载后请修改扩展名

posted on 2006-03-28 09:40 jzhang 阅读(15613) 评论(168)  编辑 收藏

评论

# re: 一段Python程序和C程序的对比

我也感觉python不错,目前正在学习,相信以后会很流行
2006-03-28 11:07 | usr_root

# re: 一段Python程序和C程序的对比

算法明显不一样,你这比较的是hash和list性能的差别,而不关python和C任何事。
我也想看看python性能如何,请问能不能把你的txt文件发一份给我?
2006-03-28 12:16 | 周星星

# 用lua测了一下, 结果差不多

最近正在看lua, 所以也测了一下
在p4 2.4上约0.33秒, 用来完成实际任务的代码也是11行
t1 = os.clock();
email = {}
f = io.open("email_new.txt", "wt+")
for line in io.lines("email.txt") do
if #line > 0 then
if email[line] == nil then
email[line] = 1
f:write(line, "\n")
end
end
end
f:close()

print( string.format("time used: %f seconds", os.clock() - t1) );
2006-03-28 12:48 | 局部变量

# 先帮我测试一下这段C++代码所耗费的时间(release版本)

#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <algorithm>
#include <iterator>
using namespace std;

int main( void )
{
    vector<string> emails;
    {
        ifstream infile( "email.txt" );
        copy( istream_iterator<string>(infile), istream_iterator<string>(), back_inserter(emails) );
    }
    sort( emails.begin(), emails.end() );
    emails.erase( unique( emails.begin(), emails.end() ), emails.end() );
    {
        ofstream outfile( "email_new.txt" );
        copy( emails.begin(), emails.end(), ostream_iterator<string>(outfile,"\n") );
    }
}

2006-03-28 12:49 | 周星星

# 我自己测试了一下

PM 2.0G 内存 1G,其实这些参数用处不大,主要要看硬盘的读写速度,我用的是笔记本硬盘。
测试结果是 499.9584毫秒,这个数字还是比较准确的,好多次都是这个值。
2006-03-28 13:02 | 周星星

# C的代码也是一种hash算法

测试的文件在原文有链接的。是一个rar文件,扩展名被改成了txt
2006-03-28 13:05 | jzhang

# Lua也是很有名的

不过我不打算同时学习两种脚本,Python的最大的缺点其实就是慢。我举的这个例子,其实是为了说明算法不同带来的性能差异往往比语言本身要大得多。
2006-03-28 13:07 | jzhang

# 看来应该把测试文件扩大10倍

这样才能体现出差异来。
2006-03-28 13:08 | jzhang

# 周星星你的算法比Python的慢

我测试的780000条记录的情况:
Python版本:3200 ms
C++版本:5700 ms

都是多次的平均值。我想主要是排序花的时间太多了。
2006-03-28 13:18 | jzhang

# 测试的数据文件

http://jason.rocklv.net/downloads/email.rar
2006-03-28 13:22 | jzhang

# 我发现lua的语法根Python蛮像的

t1 = os.clock();
email = {}
f = io.open("email_new.txt", "wt+")
for line in io.lines("email.txt") do
if #line > 0 then
if email[line] == nil then
email[line] = 1
f:write(line, "\n")
end
end
end
f:close()

print( string.format("time used: %f seconds", os.clock() - t1) );
尤其是hash表的申明和使用,都是内置支持。就是这个end让我看着难受点,呵呵
2006-03-28 13:24 | jzhang

# 试试hash_set的性能

#include <iostream>
#include <hash_set>
#include <string>
#include <fstream>
#include <windows.h>

int main( void )
{
    __int64 t1, t2;
    GetSystemTimeAsFileTime( (LPFILETIME)&t1 );

    std::ifstream infile( "email.txt" );
    std::ofstream outfile( "email_new.txt" );
    stdext::hash_set<std::string> emails;
    for( std::string email; infile>>email; )
    {
        if( emails.insert(email).second )
        {
            outfile << email << '\n';
        }
    }

    GetSystemTimeAsFileTime( (LPFILETIME)&t2 );
    printf( "经过了%I64d.%04I64d毫秒\n", (t2-t1)/10000, (t2-t1)%10000 );
}

我这里需要 437.4636 毫秒

2006-03-28 13:35 | 周星星

# re: 一段Python程序和C程序的对比

在我的机器上,用78万条的那个文件,对python(2.4), c++(hash_set版, vs2003, release, 打开各种优化), lua(5.1)三种语言进行了测试
结果如下:
顺序   语言    时间(毫秒)
1      c++     72025
2      python   4720
3      lua      3312
4      lua      3281
5      python   4735
6      c++     72540
c++的表现简直太让我失望了,不知是否那里做的不对?

另:to jzhang, 一个完整的lua只有100多K, python却要20多M, 所以我更喜欢lua
2006-03-28 14:04 | 局部变量

# to 局部变量,你测试的是周星星的第一个版本吧?

他用的是list+排序的算法。性能比hash差得多,而且文件越大越差。
这不是语言的问题了。
不过看起来Lua的确比Python快,在相同算法的情况下。

100k的Lua能做什么?Python的体积主要也来自他的丰富的库。

ps.为什么你每次都回复3篇?....浏览器的bug?
2006-03-28 14:38 | jzhang

# 发现几个奇怪的地方

1。我以为 set 会比 hash_set 慢一些,但发现和 hash_set 一样,仍然是 437.4636 毫秒,代码如下:
#include <iostream>
#include <set>
#include <string>
#include <fstream>
#include <windows.h>
using namespace std;

int main( void )
{
    __int64 t1, t2;
    GetSystemTimeAsFileTime( (LPFILETIME)&t1 );

    ifstream infile( "email.txt" );
    ofstream outfile( "email_new.txt" );
    set<string> emails;
    for( string email; infile>>email; )
    {
        if( emails.insert(email).second )
        {
            outfile << email << '\n';
        }
    }

    GetSystemTimeAsFileTime( (LPFILETIME)&t2 );
    printf( "经过了%I64d.%04I64d毫秒\n", (t2-t1)/10000, (t2-t1)%10000 );
}

2。同样的代码,我以为 dev-cpp 编译出来比 vc2005 慢一些,但发现每次都一样

3。我以为在调试器中运行 会比 直接在控制台下运行 慢一些,但发现结果恰恰相反,而且差距很大:
VC8中运行平均500毫秒 ,dev-cpp中运行平均430毫秒,dev-cpp编译的程序在CMD中运行平均530毫秒,dev-cpp编译的程序在CMD中运行平均530毫秒

4。g++的 hash_map 运行不起来
#include <string>
#include <ext/hash_map>
using namespace std;
using namespace __gnu_cxx;

namespace __gnu_cxx
{
        template<> struct hash<const string>
        {
                size_t operator()(const string& s) const
                { return hash()(s.c_str()); }
        };
        template<> struct hash<string>
        {
                size_t operator()(const string& s) const
                { return hash()(s.c_str()); }
        };
}

int main( void )
{
        hash_map<string,int> a;
        a["abc"] = 1; // 这一句一执行的话,程序直接退出

        system("pause");
}

2006-03-28 14:38 | 周星星

# To 周星星

你的hash版本测试的是78000的还是780000的?
2006-03-28 14:38 | jzhang

# To 周星星 again

1.难道Set内部的实现也是hash?
2.用780000的那个文件测试,我想调试器版本应该更慢了

ps.我以前从来不用C++的标准库,呵呵,现在看星星写的几段代码,
发现用标准库写的C++代码挺美的。:)

2006-03-28 14:43 | jzhang

# re jzhang:

78000,没有修改编译器的任何优化项
2006-03-28 14:43 | 周星星

# 测试一下780000的那个吧,我觉得那个更加准确

几百毫秒的数据比较容易被一些其他因素干扰。
2006-03-28 14:47 | jzhang

# re jzhang:

1。set 内部使用的是 RB-Tree,比 hashtable 性能差,但稳定

2。^_^ 追求代码简洁的话,只需要四句:
#include <set>
#include <string>
#include <fstream>
#include <algorithm>
#include <iterator>
using namespace std;

int main( void )
{
     ifstream infile( "email.txt" );
    set<string> emails = set<string>( istream_iterator<string>(infile), istream_iterator<string>() );
    ofstream outfile( "email_new.txt" );
    copy( emails.begin(), emails.end(), ostream_iterator<string>(outfile,"\n") );
}

2006-03-28 14:48 | 周星星

# 呵呵,这段代码可不美

需要看几眼才能看明白一行的代码不好,:)
2006-03-28 14:51 | jzhang

# 跟Python版本差不多

这真是一个证明Python某些地方也挺快的好例子呀,呵呵。
其实Python慢的最重要原因之一是它的动态类型,而这个例子里
并没有体现,所以性能就跟C++不相上下了。

我现在的项目就要用STL了,希望能在1个月之内用熟
2006-03-28 15:01 | jzhang

# to jzhang

我也不知道为什么每次都是3个,害得我都有点不敢回复了:(
我用的就是那个hash_set的版本, 不知道为什么那么费时间
lua自带string,math,table,io,debug库(确实是比python少多了),不过它应该主要还是用在内嵌脚本上吧,我现在研究它也是打算在一个项目中使用它处理脚本
2006-03-28 15:01 | 局部变量

# re jzhang:

把我上一个帖子删除掉,因为我把780000说成了78000。更改如下:

我用 780000 的做测试用例,代码如下:
ifstream infile( "email.txt" );
set<string> emails = set<string>( istream_iterator<string>(infile), istream_iterator<string>() );
ofstream outfile( "email_new.txt" );
copy( emails.begin(), emails.end(), ostream_iterator<string>(outfile,"\n") );
平均值是 4900 毫秒。
2006-03-28 15:04 | 周星星

# to 局部变量,每次我都要删除你的两个回复,:P

赶快请站长帮忙解决吧~你用的什么浏览器啊?
其实内嵌脚本用什么都无所谓,我用过Python,也用过TCL,
原理都是一样的。反正这些语言在这种场合只是做胶水的,有基本的
语言要素就可以了。
2006-03-28 15:04 | jzhang

# re: 一段Python程序和C程序的对比

std::string和stream可能都有些性能问题。hash_set好像还不如set,hash_set本身有另外一个性能问题。
我用楼主的测试基本上是320MS
2006-03-28 15:22 | sevencat

# re: 一段Python程序和C程序的对比

哪位把更大的发给我,我测一下时间。
2006-03-28 15:25 | sevencat

# re: 星星,如果你对这个算法感兴趣,可以研究一下我的这篇

 

查找序列中给定 对象组合 的模板类

2006-03-28 15:30 | Panic

# re: 一段Python程序和C程序的对比

我又优化了一下,能达到240MS
2006-03-28 15:32 | sevencat

# 测试文件的地址:

78000的: http://jason.rocklv.net/downloads/email2.txt (注意这是个rar)
780000的: http://jason.rocklv.net/downloads/email.rar
2006-03-28 15:32 | jzhang

# re: 一段Python程序和C程序的对比

我怀疑大家被这个东东忽悠了。这个完全不是算法瓶颈,仅仅是文件IO瓶颈,可以试试用FILE,setvbuf(18*1024)看看。
我这里C++比PYTHON要快。我这边一般在3000MS以下。而python基本上会在4000MS以上。
2006-03-28 15:47 | sevencat

# 这也有可能

不知道标准库的文件缓冲区是多大,C的默认是4k吧。当然这个缓冲区越大会越快。嗯,这的确是一个因素。
2006-03-28 15:53 | jzhang

# re: 一段Python程序和C程序的对比

这已经是最主要的因素了。
你可以试试一开始把数组全部读出来,开始计时,然后进行判断,再结束,再写,这样,可能就很清楚了。我不知道python的机制是什么,其实这种读大型文件,还有另外的更快的机制。
2006-03-28 15:55 | sevencat

# 恩,我本来也不认为Python比C快

但是Python在某些情况下可以跟C一样快,:)
2006-03-28 16:06 | jzhang

# re: 一段Python程序和C程序的对比

不过这种比较已经没啥意义了,C是那么的难用,C++是那么的更难用....
2006-03-28 16:12 | sevencat

# re: 一段Python程序和C程序的对比

# re jzhang: 
把我上一个帖子删除掉,因为我把780000说成了78000。更改如下: 

我用 780000 的做测试用例,代码如下: 
ifstream infile( "email.txt" ); 
set<string> emails = set<string>( istream_iterator<string>(infile), istream_iterator<string>() ); 
ofstream outfile( "email_new.txt" ); 
copy( emails.begin(), emails.end(), ostream_iterator<string>(outfile,"\n") ); 
平均值是 4900 毫秒。 
2006-03-28 15:04 | 周星星 

嗯,那这样的呢
    ifstream infile( "email.txt" );
    ofstream outfile( "email_new_my.txt" );

    unique_copy( istream_iterator<string>(infile), istream_iterator<string>(), ostream_iterator<string>(outfile,"\n"));
time_t end = time(NULL);
2006-03-29 10:55 | imjj

# re imjj:

使用 unique_copy  的话,仍然需要先排序,假设email.txt内容如下:
b
a
a
b
使用 unique_copy  得到的将是
b
a
b
也就是 unique_copy  只会将相邻而重复的取 unique。
2006-03-29 13:59 | 周星星

# re: 周星星

嗯 受教
试了一下 果然如此
2006-03-29 20:19 | imjj

# re: 一段Python程序和C程序的对比

嗯 查了Python的源码 基本搞清楚了对于这个例子Python为什么这么相当的快,在$PySrc/Objects/descrobject.c 中,对Python的Hash机制作了一些描述,总的来说,Python的Hash机制对于这种连续型的字符串有相当好的离散度,对于这个 78W 例子,python_hash() % 780000能够很均匀的分散到各个值,最大的冲突数为 8(通常的算法要到2K+)。也大概看了看Lua的实现,Lua 的Hash算法同样很适合这样的例子,但是Lua本身的开销小,所以它的速度比Lua还快。

再一个 ifstream 和 ofstream 的性能也是 C++ 实现不如这些脚本实现速度快的一个因素,当重复的调用 ofstream<< ,而不是使用 copy 等 alogrithm 的相关方法输出时,这个性能实在有点慢,而使用 fgets/fprintf 就好的多。

以下是按照类似 Python的 Hash算法实现的 C++ 版本的结果
E:\Workspace\Temp\Email>my
经过了1687.5000毫秒

E:\Workspace\Temp\Email>my
经过了1718.7500毫秒

E:\Workspace\Temp\Email>my
经过了1671.8750毫秒

E:\Workspace\Temp\Email>my
经过了1656.2500毫秒

E:\Workspace\Temp\Email>py_email.py
2.82014641526

E:\Workspace\Temp\Email>py_email.py
2.74879181572

E:\Workspace\Temp\Email>py_email.py
2.76348586203

E:\Workspace\Temp\Email>dir *.txt
2006-03-28  13:09        19,388,869 email.txt
2006-03-29  22:51        17,779,266 email_new.txt (py_email.py 写出)
2006-03-29  22:50        17,779,266 email_new_my.txt (my.exe 写出)

py_email.py 的实现参看楼主的实现
my.cpp 实现如下
使用 cl /O2 /EHsc /D_CRT_SECURE_NO_DEPRECATE my.cpp 编译

#include <cstdio>
#include <windows.h>
using namespace std;


#define c_mul(a, b) (a * b & 0xFFFFFFFF)

size_t python_hash(const char * str)
{
size_t value = str[0] << 7;
size_t len = 0;
while(*str != 0)
{
value = c_mul(1000003, value) ^ *str++;
len++;
}

value = value ^ len;
if (value == (size_t)-1)
value = (size_t)-2;
return value;

}

size_t hash(const char * str, size_t seed = 1)
{
size_t h = 0, g; 
size_t len = 0;
while (*str) { 
h = (h << 4) + *str++; 
if ((g = (h & 0xF0000000))) { 
h = h ^ (g >> 24); 
h = h ^ g; 
h = h ^ seed;

len++;

return h; 
}


#define MAX_TABLE_SIZE (780000)
#define MAX_CONFI 9

struct hash_item
{
size_t items[MAX_CONFI];
size_t item_count;
hash_item()
{
item_count = 0;
}
bool check_has(const char * str)
{
size_t key = hash(str);
for(size_t i = 0; i < item_count; i++)
{
if (items[i] == key)
return true;
}
items[item_count++] = key;
return false;
}

};


int main( void )
{
__int64 t1, t2;
    GetSystemTimeAsFileTime( (LPFILETIME)&t1 );
    FILE * fin = fopen("email.txt", "r");
FILE * fout = fopen("email_new_my.txt", "w+");

size_t hash_key_a = 0;
size_t hash_key_b = 0;
size_t pos_x = 0;
size_t pos_y = 0;
const char * buffer = NULL;
char line[255];
fgets(line, 255, fin);
hash_item * table = new hash_item[MAX_TABLE_SIZE];
while(!feof(fin))
{
buffer = line;
hash_key_a = python_hash(buffer);
pos_x = hash_key_a % MAX_TABLE_SIZE;
if (!table[pos_x].check_has(buffer))
{
fprintf(fout, "%s", buffer);
}

fgets(line, 255, fin);
}
    GetSystemTimeAsFileTime( (LPFILETIME)&t2 );
    printf( "经过了%I64d.%04I64d毫秒\n", (t2-t1)/10000, (t2-t1)%10000 );
fclose(fin);
fclose(fout);
delete [] table;
}
2006-03-29 23:33 | imjj

# imjj 真棒!

研究得这么透彻,受益匪浅。
2006-03-30 08:51 | jzhang

# re: 一段Python程序和C程序的对比

可能是因为很多人被误导了,以为STL的东东效率高,其实不是那么回事。stl的基于node的都有性能问题。std::string也有性能问题。(因为都有动态分配内存过程)
2006-03-30 09:01 | sevencat

# STL

STL的效率不是高,而是不比你写的低,我觉得STL首先保证通用性,其次保证使用的算法复杂度,最后才考虑性能,而且不同的算法和容器使用在不同场合有不同的性能(取决于其实现),内存分配也是可定制的,通用的alloctor并不适用所有情况的需求
2006-03-30 10:38 | ksl

# 通用的效率一定就低吗?

而且,作为一个标准库,性能应该是和通用性同等重要的指标,更何况还是非常常用的数据结构呢。
2006-03-30 10:56 | jzhang

# re: 一段Python程序和C程序的对比

比我写的优化过后的肯定要低的。在效率要求高的地方,不太会考虑STL的东东的。
2006-03-31 06:59 | sevencat

# 为何Python这么快 [TrackBack]

为何Python这么快
zfive5引用了该文章,地址:http://blog.csdn.net/zfive5/archive/2006/03/31/645244.aspx
2006-03-31 08:29 | zfive5

# re: 一段Python程序和C程序的对比

这个完全取决于实现。我在我的机器上测试了一下,这个python程序运行耗时:
lijie ~ # python test.py
0.437092065811
lijie ~ # python test.py
0.473711013794
lijie ~ # python test.py
0.452960014343
lijie ~ # python test.py
0.469227075577
lijie ~ # python test.py
0.42777299881
lijie ~ # python test.py
0.415369987488

415-473毫秒之间。

我用D语言写了一个,调用fopen, fgets, fputs这些函数的,运行结果如下:

lijie ~ # ./email email.txt email-new.txt
132
lijie ~ # ./email email.txt email-new.txt
137
lijie ~ # ./email email.txt email-new.txt
145
lijie ~ # ./email email.txt email-new.txt
138
lijie ~ # ./email email.txt email-new.txt
148
lijie ~ # ./email email.txt email-new.txt
143

单位是毫秒。
我查看了输出文件,是一样的。

D版本的代码如下:
import std.stdio;
import std.string;
import std.perf;

int main(char[][] argv)
{
  if (argv.length < 3) {
    writefln("Wrong arguments");
    return 1;
  }

  const int READ_SIZE = 1024;

  FILE* fin = fopen(argv[1], "r");
  FILE* fout = fopen(argv[2], "w");
  char buffer[READ_SIZE];
  int[char[]] emails;

  PerformanceCounter counter = new PerformanceCounter();
  counter.start();
  while (!feof(fin)){
    fgets(cast(char*)buffer, READ_SIZE, fin);
    char[] email = toString(cast(char*)buffer);
    if (!(email in emails)){
      emails[toString(buffer)] = 0;
      fputs(cast(char*)email, fout);
    }
  }

  fclose(fout);
  fclose(fin);
  counter.stop();

  writefln(counter.milliseconds());
  return 0;
}
由于是在上班,没花时间处理文件打开失败等情况,见谅。
2006-03-31 10:28 | cpunion

# re: 一段Python程序和C程序的对比

测试大文件780000行那个:
python:单位:秒
lijie ~ # python test.py
5.0066409111
lijie ~ # python test.py
4.827917099
lijie ~ # python test.py
4.76066708565

D:单位:毫秒
lijie ~ # ./email email-2.txt email-2-new.txt
1425
lijie ~ # ./email email-2.txt email-2-new.txt
1354
lijie ~ # ./email email-2.txt email-2-new.txt
1413
2006-03-31 10:38 | cpunion

# re: 一段Python程序和C程序的对比

忘了关浏览器了,而浏览器正好打开了级度耗资源的CSDN。重新测试了一下:

lijie ~ # python test.py
3.27638888359
lijie ~ # python test.py
3.31844902039
lijie ~ # python test.py
3.31299114227
^[[Alijie ~ # python test.py
3.41847610474
lijie ~ # python test.py
3.32070493698
lijie ~ #
lijie ~ # ./email email-2.txt email-2-new.txt
1131
lijie ~ # ./email email-2.txt email-2-new.txt
1128
lijie ~ # ./email email-2.txt email-2-new.txt
1114
lijie ~ # ./email email-2.txt email-2-new.txt
1125
lijie ~ # ./email email-2.txt email-2-new.txt
1122

这个D语言版本比python版本快3倍左右。由于D对C的包装也比较薄,基本上可以认为是C语言的效率。使用纯C应该会更高,不过我没能力实现出一个这么高次的关联数组。
(注:上面这个D版本使用了关联数组模拟set行为)

发太多了,好像灌水似的,见谅
2006-03-31 10:44 | cpunion

# D语言?第一次看见,开了眼界了,呵呵

谢谢cpunion.
2006-03-31 11:27 | jzhang

# 用快速排序达到200毫秒级算法

from datetime import datetime
if __name__ == '__main__':
print(datetime.today())
f = file(r'E:\email.txt','r')
lines1, lines2 = f.readlines(), [];
f.close()
lines1.sort()
lines2.append(lines1[-1])
for ln in range(len(lines1) - 2, -1, -1):
if lines1[ln] <> lines1[ln + 1]: 
lines2.append(lines1[ln])
f = file(r'E:\email_new.txt','w')
f.writelines(lines2)
f.close()
print(datetime.today())

2006-03-31 12:03 | m

# re: 一段Python程序和C程序的对比

还可以不采用lines2,而直接在lines1上将相同的串置空串,这样效率还可以提高。
2006-03-31 12:06 | m

# re: 一段Python程序和C程序的对比

数据可能还是不够复杂,email仅仅前几位有差异,这样通过strcmp也只需要比较前几位,可以试着把它倒转,让尾部几个字符不同,再比较一下效率。这样使用字符串比较的应该会受到影响吧
2006-03-31 12:33 | cpunion

# m,你的算法吃内存太厉害了

一次把文件全部读出来了。
2006-03-31 12:51 | jzhang

# re: 一段Python程序和C程序的对比

大批量插入,hashMap会比treeMap好很多。极端情况下会差10倍以上。我以前试过了
2006-03-31 13:09 | wmuu

# re: 一段Python程序和C程序的对比

c++的map是用二叉数字实现的,极端情况下每次插入会和每个已有的元素进行比较
2006-03-31 13:11 | wmuu

# re: 一段Python程序和C程序的对比

C++复杂?是你不会写C++吧:
#include <fstream>
#include <windows.h>
#include <iterator>
#include <algorithm>
#include <string>
#include <iostream>
#include <vector>
using namespace std;

int main()
{
    DWORD start = ::GetTickCount();
    vector<string> mails;
    mails.reserve(80000);

    copy(istream_iterator<string>(ifstream("email.txt")),   istream_iterator<string>(),     back_inserter(mails));
    sort(mails.begin(), mails.end());
    unique_copy(mails.begin(), mails.end(), ostream_iterator<string>(ofstream("out.txt"), "\n"));

    cout << ::GetTickCount() - start;
    return 0;
}
命令行:
cl /GX /O2 /NDEBUG b.cpp
输出:375ms
2006-03-31 14:15 | 非典型秃子

# re: 一段Python程序和C程序的对比

优化一下IO的:
#include <string>
#include <iostream>
#include <fstream>
#include <iterator>
#include <windows.h>
#include <algorithm>
#include <ios>
#include <functional>
#include <vector>
using namespace std;

void splite(char * buf, long size, vector<char*>& v)
{
v.push_back(buf);
for (;size > 0 && *buf != '\0'; ++buf, --size)
{
if (*buf == '\r')
{
*buf = '\0';
buf += 2;
size -=2;
if (*buf != '\0')
v.push_back(buf);
}
}
}
struct Comp : public binary_function<char*, char*, bool>
{
bool operator()(char * lsh, char* rsh)
{
return strcmp(lsh, rsh) < 0;
}
};
struct Comp2 : public binary_function<char*, char*, bool>
{
bool operator()(char * lsh, char* rsh)
{
return strcmp(lsh, rsh) == 0;
}
};

struct iterator_string
{
struct assigner
{
assigner(vector<char>& v) : m_v(&v){}
assigner& operator=(char* src)
{
while( *src != NULL)
m_v->push_back(*src++);
m_v->push_back('\r');
m_v->push_back('\n');
return *this;
}
private:
vector<char>* m_v;
};
iterator_string(vector<char>& v) : m_assign(v){}
assigner& operator*()
{
return m_assign;
}
iterator_string& operator++() {return *this;}
iterator_string& operator++(int) {return *this;}
private:
assigner m_assign;
};

int main()
{
DWORD start = ::GetTickCount();

ifstream ifs("email.txt" , ios_base::binary | ios_base::in);
ifs.seekg(0, ios_base::end);
long size = ifs.tellg();
ifs.seekg(0, ios_base::beg);

char* buf = new char[size + 1];
ifs.read(buf, size);
buf[size] = '\0';
vector<char*> v;
v.reserve(80000);
splite(buf, size, v);

sort(v.begin(), v.end(), Comp());

vector<char> vout;
vout.reserve(size);

ofstream ofs("out.txt", ios_base::binary | ios_base::out);
unique_copy(v.begin(), v.end(), iterator_string(vout), Comp2());
ofs.write(&vout[0], vout.size());

cout <<  ::GetTickCount() - start;
return 0;
}

简单优化一下IO,没有使用任何平台相关的技巧,最好输出时间:78ms
我的机器:
p42.66 , 1G RAM,硬盘ST380011A

为什么一定要和C++比性能呢?即使比简洁,C++也不落后啊。
2006-03-31 14:26 | 非典型秃子

# re: 一段Python程序和C程序的对比

你下那个稍微大点的email.txt试试吧。
2006-03-31 14:38 | sevencat

# re: 一段Python程序和C程序的对比

78000的: http://jason.rocklv.net/downloads/email2.txt (注意这是个rar)
780000的: http://jason.rocklv.net/downloads/email.rar
下第2个,用python和C++来试。
2006-03-31 14:39 | sevencat

# re: 一段Python程序和C程序的对比

其实 多跑第二次的时候 基本读就没有真正的磁盘IO了 源数据都在内存里cache着 除非再做一堆磁盘IO 把cache里的老数据挤出去
另外 儿叉树未必会比hash table慢 对具体的这个问题来说 一般的字符串hash算法 算hash值需要把每个字符算一遍 如果每个串比较长 就会比较慢 虽然好的算法基本能一次查找到 但是算key的时间可能比较长 而二叉树虽然需要多次比较 但是如果任意两个串 在开头的几个字符就很可能不同的话 每次字符串比较大小只需要比较很少的几个字符 所以最终的速度非常依赖于每行字符的特征 
关于字符串的问题总是比较复杂的......
2006-03-31 17:21 | TripleX

# to 非子,你的算法和星星的是一样的

另外,测试的时候你有对比测试其他程序的吗?否则机器的差别太大了。
2006-03-31 18:30 | jzhang

# To triplex

hash code算起来虽然慢,但是比起字符串比较来说,差的很远。
hash code的计算开销基本是固定的
2006-03-31 18:33 | jzhang

# re: 一段Python程序和C程序的对比

大文件,似乎文件cache不会把所有的都cache进来。

我自己的测试都是先跑几次“热热身”,然后再做的。
2006-03-31 20:32 | sevencat

# re: 一段Python程序和C程序的对比

hash_code比起那些动态分配内存起来,简直是小儿科
2006-03-31 21:09 | sevencat

# re: 一段Python程序和C程序的对比

to sevencat
在这个程序里 动态内存分配应该不太费 因为整个过程都不free内存
意味着分配会一直发生在堆的尾部 可用空间表里就一个指针 没有任何碎片 也不需要往后查找可用块...... 只是偶尔会引发一个brk调用
如果这个程序是一个大程序的一部分 可能会在运行一段时间后显著的减慢 
2006-03-31 22:38 | TripleX

# re: 一段Python程序和C程序的对比

我看了测试数据,这个数据明显是假造的,测不出实际应用时的情况。
2006-03-31 22:51 | Lyons

# re: 一段Python程序和C程序的对比

to jzhang
set是一个rb-tree 字符串的比较只是比较大小 其实是从左往右
比较到第一个不同的字符 我当时测试文件用的是一个base64
编码的文件 每行都是78个ascii字符 基本上前几个都不相同
所以平均比较不到五个字符就可以判断出大小了 78k个字符串
在set里应该平均不超过20级深度(我猜的 没有去debug) 所以
每次找一个字符串是不是在set里 也就不到100次比较 而我用的
算hash_key的方法每次都要做78次乘法 ...我是在我的iBook G4
800MHz上跑的 用time命令测试时间 只计算用户态下的时间 
这样阻塞在磁盘IO和文件系统耗费的时间都没算 c和c++耗费
时间的比大概是300ms vs 800ms 文件是一个76k行的base64
文件  每行78个字符  c用手工实现的hash table  c++用的是set
rb-tree的性能还可以接受了 至少用stl的代码短多了 呵呵 
rb-tree耗费比较大的另外一个原因可能是cache miss 因为
在树里每走一级都要通过指针访问一个内存地址 而这些内存
地址是分散在一个很大的空间里的 cache miss的概率比较大
在有大cache的机器上 表现应该好不少 比如2M cache的
PentiumM 不过话说回来 2M cache基本可以把hash_table
整个放在里边了  
2006-03-31 23:04 | TripleX

# re: 一段Python程序和C程序的对比

to sevencat
在linux下 文件io都是先读到内核的page cache的 只要可用的
页没有降低到一定的水平 这些页里的数据就不会失效 对这些
几M大小的文件 全被cache住是很正常的 对于写操作 也是写到
page cache 里 然后把dirty位设上 等待磁盘io调度的内核线程写入
 
2006-03-31 23:29 | TripleX

# re: 一段Python程序和C程序的对比

说的有点不精确 其实write并不等待自己标记的页被写入 而是直接
返回 未来的某个时候页才会被写 write调用等待一般是因为没有
物理页可用了 所以write调用会被阻塞 等待io线程把脏页回写 
然后把那些物理页释放出来 而io线程一般会多回写一些页 每次
释放比请求的更多的页 这个就是看具体的vm的行为了
2006-03-31 23:35 | TripleX

# re: 一段Python程序和C程序的对比

贴一下我测试用的c++代码 c代码就是上面那个
没怎么写过c++代码 基本套着c的路子写的 呵呵
#include <set>
#include <string>
#include <fstream>
#include <iostream>

using namespace std;
#define LINE_MAX_LEN 1024

int main(int argc, char **argv)
{
        char buf[LINE_MAX_LEN];
        ifstream infile;
        ofstream outfile;
        string str;
        set <string> tbl;

        if(argc != 3) {
                printf("error: \nplease use eml as:\n eml infile outfile\n");
                return -1;
        }
        infile.open(argv[1]);
        outfile.open(argv[2]);
        while(infile.getline(buf, LINE_MAX_LEN)) {
                str = buf;
                if(tbl.count(str) == 0) {
                        outfile << str << endl;
                        tbl.insert(str);
                }
        }

        return 0;
}
2006-03-31 23:49 | TripleX

# re: 一段Python程序和C程序的对比

to:TripleX :从表面上来看的确不用free,但至少std::string的那些栈上的内存是FREE的,(LINUX下可能会好些,因为LINUX的std::string是引用计数的,但VC的不是),假如用的是hash_set的话,他的每个bucket也有可能会free(因为重新分配导致的),你说的那个cache是linux下的情况,linux有的版本甚至会有因为文件cache占用住 所有的内存的情况(连交换内存都占光了),但WIN下面可能不是这样的。至少write的那个,一般情况的确是这样,除了另外一种情况,有时候有人会把那个异步写的标志关闭,不过这些都是题外话了。
2006-04-01 12:05 | sevencat

# Python的效率来源于C

实际上,Python程序只是对C的系统调用,大部分
代码在C里,这种比较并不能看出Python效率高于C++。

非典型秃子 的算法有点问题,unique_copy只是
判断相邻的元素是否相同。
2006-04-01 16:02 | dwbclz

# 我的C++程序

使用那个大文件作了测试
python: 4.2s
cpp: 1.85s

由于内容太长,不能完全发出来,所以请参见:
http://blog.csdn.net/imjj/archive/2006/03/31/645163.aspx

是别人的blog,我也是去瞎搅和的。
2006-04-01 16:28 | dwbclz

# re: 一段Python程序和C程序的对比

// mail.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include <hash_set>
#include <set>
#include <iostream>
#include <fstream>
#include <windows.h>

using namespace std;
using namespace stdext;

const char* IN_FILE_NAME = "email.txt";
const char* OUT_FILE_NAME = "out.txt";

void testmail();
int hash_code(const char* p);

int _tmain(int argc, _TCHAR* argv[])
{
    __int64 t1, t2;
    for(int i = 0; i<3; ++i){
        GetSystemTimeAsFileTime( (LPFILETIME)&t1 );
        testmail();
        GetSystemTimeAsFileTime( (LPFILETIME)&t2 );
        printf( "经过了%I64d.%04I64d毫秒\n", (t2-t1)/10000, (t2-t1)%10000 );
        Sleep(1000);
    }
    getchar();
    return 0;
}

int hash_code(const char* p){
    int hash =0;
    while(*p){
        hash= 31*hash+*(p++);
    }
    return hash;
}

void testmail(){
    ifstream infile;
    ofstream outfile;
    set<int> ht;
    char buf[100];

    infile.open(IN_FILE_NAME);
    outfile.open(OUT_FILE_NAME);

    while(infile.getline(buf, sizeof(buf))){
        int hash = hash_code(buf);
        if(!(ht.insert(hash)).second){
            continue;
        }
        outfile<<buf<<"\n";
    }
    return;
}

我参考python代码写的c++代码,应该是最接近python的代码的代码。hash_code是参考java的String,这应该没问题吧,这两个最近好像也在吵。 
E:\c\mail\Release>mail 
经过了3062.5000毫秒 
经过了3125.0000毫秒 
经过了3140.6250毫秒 

E:\c\mail>email.py 
4719.00010109 

E:\c\mail>email.py 
4657.00006485 

E:\c\mail>email.py 
4750.0 

在基本相同的算法,基本相同的过程下,python,java是比不过c++的。
2006-04-01 17:34 | wmuu

# 跑到别人的blog上去看了看

简直变成了一场论战...
wmuu说: 在基本相同的算法,基本相同的过程下,python,java是比不过c++的。
这根本就是不言自明的,那么多人去实现那么复杂的算法来证明上面的那个道理,我觉得真是奇怪.还有人指责说我的测试文件是造假,好像我要故意欺骗谁一样....其实我只是想说,Python有的时候挺好用的,呵呵.
2006-04-01 18:26 | jzhang

# re: 一段Python程序和C程序的对比

to jzhang
你说Python有的时候挺好用的。本身没什么问题啊。
但是关键你用比较夸张的c/c++代码来和python代码比较,然后再得出这个结论,那就让人很不爽了。
2006-04-01 18:45 | wmuu

# re: 一段Python程序和C程序的对比

C++也可以很简洁。 
看了周星星的回帖,想到不一定要比较效率,其实可以 
考虑简洁性。两行代码解决问题: 

set<string> emails( istream_iterator<string>(ifstream("email.txt")), istream_iterator<string>() ); 
copy( emails.begin(), emails.end(), ostream_iterator<string>(ofstream("email_new.txt"),"\n") ); 

如果使用VC7.1编译,耗时5.1s 
如果使用STLport(5.0.2),耗时2.7s 
python的程序在我的电脑上,耗时4.2s 
所以说,呵呵……

以前不怎么用C++的流,周星星的用法还是让我学到一些东西的。 

另外,周星星初始化emails多了一次 set 的复制操作,其实
没有必要。
2006-04-01 19:08 | dwbclz

# re: 一段Python程序和C程序的对比

to jzhang 

同意wmuu的观点。你说Python有的时候挺好用的。本身没什么
问题啊。但是编写不太那个C++代码来比较就有点问题了。
这样做会给一些初学者一些不太正确的想法。其他人可能产生
“C++低效”的误解,这样并不好。

实现C++的代码本来也用不着那么麻烦,上面就已经给出了
很简洁的实现,效率如何也说了的。

至于使用那些麻烦的东西,那是C++爱好者的内部探讨,并非
单纯为了跟python比较了。对效率的优化不限于语言,麻烦的
东西并非为了证明C++的效率,而是为了研究如何提高效率。
2006-04-01 19:34 | dwbclz

# re: 一段Python程序和C程序的对比

我给段稍为快点的python代码:
import time
if __name__ == "__main__":
 t = time.time() 
 s = set()
 f = file("email.txt","r")
 f2 = file("email_new.txt","w")
 s.update(f.readlines())
 for line in s:
   f2.write(line)
 f.close()
 f2.close()
print time.time() - t
用set来过滤重复的行
2006-04-01 20:35 | 3751

# re: 一段Python程序和C程序的对比

其实如果c++代码写得比python代码慢,那只能说明那c++代码写得烂,正常情况下c++绝对会比python快的。
2006-04-01 20:39 | 3751

# re: 一段Python程序和C程序的对比

汗,用set的办法,原来已经有人在c++里面用了。还没看完就发贴了。
2006-04-01 20:44 | 3751

# re: 一段Python程序和C程序的对比

import Data.Set

main = readFile "email.txt" >>= writeFile "email2.txt" . unlines.toList.fromList.lines

Haskell一行,就是太慢了,用list实现的string效率太低。
2006-04-02 00:12 | quhw

# re: 一段Python程序和C程序的对比

to wmuu:
  我想你搞错了 jzhang贴的代码是C代码 基本上是ansi c标准的
(除了宏定义可能有点不标准) 和c++根本不沾边 这个代码用new
做变量 在c++编译器里编译不可能通过的 你说的用夸张的c++代码
和python代码比 是不恰当的 他在标题里说的是c 不是c++ 
c++标准库里有不错的算法 但是c标准库里很少 所以代码看起来
是会比较夸张的 
这个代码是我写的 list.h是从linux kernel里直接拷出来的 我是一个
C程序员 基本不懂c++ 我想我的代码不至于会让别人对c++有什么
不好的印象 只是 别把C代码当成c++代码读 虽然有时候C代码能
用c++编译器编译 
jzhang对性能的结论是在用cygwin编译的情况下得出的 用一个
本地的运行环境 效能肯定能好不少 比如我在OSX下测试结论就
不是这样的(0.4s vs 1.1s) 但是无论如何 一个解释执行的脚本
语言 在做某些事情的时候 效能能和编译型语言一个数量级 
已经足以让人高兴一阵子了 这显然要归功于有良好的设计 
例如在这里 如果没有字典类型 python的表现就不会那么好 
而在二进制数据处理的时候python就很糟糕  
而且就算c++很慢也没什么了不起 虽然我是C程序员 但是我觉得
c很容易写出不快的代码 因为缺乏一个标准的算法库 相比java
一个C语言的初学者更倾向于用数组 做线性搜索 而我见过的
java超级菜鸟都知道数据多的时候用hash table 反正有标准库
用就是了 这点上c++也是类似的 STL让大家能更方便的使用
快速的算法
C可以编写很快的程序 并不是说用C编写的程序一定很快 
2006-04-02 00:18 | TripleX

# re: 一段Python程序和C程序的对比

贴一个perl的 在我的iBookG4 800MHz上比python的几乎快一倍 
没有C的版本快
#!/usr/bin/perl
open(infile, "a");
open(outfile, "b");
while ($line = <infile>) {
        $tbl{$line} = 1;
}
while (($holder,$record) = each(%tbl)) {
        print outfile ($holder);
}
2006-04-02 00:48 | TripleX

# re: 一段Python程序和C程序的对比

重新跑了一下 快不到一倍 50%左右吧
有个小bug 程序应该是
#!/usr/bin/perl
open(infile, "a");
open(outfile, ">b");
while ($line = <infile>) {
        $tbl{$line} = 1;
}
while (($holder,$record) = each(%tbl)) {
        print outfile ($holder);

2006-04-02 01:06 | TripleX

# re: 一段Python程序和C程序的对比

Re TripleX 

或许wmuu搞错了什么吧,呵呵,我觉得我可能也搞错了,
道歉先……,就当作愚人节玩笑了吧。

不过不管怎么说,这篇文章的相关链接上了CSDN首页。
myan老师也说了“希望消除其他人可能产生的“C++低
效”的误解。C/C++被很多人看作过时的东西,尤其是
中国的一些初学者。这不太好,因为很多人因此走了一
些弯路。各种类型的语言都有其优势和劣势,正确
的理解这其中的差异还是很重要的。

C的效率跟C++是非常相似的,因此作这样的讨论也应该不算
是很离题的吧。

脚本的效率在很多时候都体现在对系统功能的有效调用,
因此,各种基于C/C++的扩展模块的效率才是关键。实际上,
Python的底层代码是C的,它的优化非常好,自然效率高。

对于通常的C程序而言,这段代码的一个很重要的问题在于
内存优化,而不是在于cygwin。我不太清楚OSX的内存操作
效率如何,但是在Windows下,内存分配和释放是很费时间
的。不管是C还是C++,优化的方向都差不多。一是要选择
正确的算法(使用table,而不是list);二是优化内存的使
用;三是正确处理IO操作。

对于下面的这个实现:
    set<string> emails( istream_iterator<string>(ifstream("email.txt")), 

istream_iterator<string>() );
    copy( emails.begin(), emails.end(), ostream_iterator<string>(ofstream

("email_new.txt"),"\n") );

在VC7.1下编译,使用18M的那个文件
使用VC标准库:耗时5.3s
使用STLport:耗时2.2s
使用python:耗时3.8s

昨天测试结果跟今天不一样,可能是因为系统里运行的程序
少了吧。

举这个例子是为了说明优化的方向,除了基本算法之外,内存
和IO应该是优化的重点。python底层是有一个专门针对小块内
存做优化的内存池的,小于256字节的内存都会以快速的方式
进行分配和释放。据说STLport的实现是内存优化过的,不过
俺没太细看过源码。

无论是C还是C++,效率都不会差,并且也不一定会很麻烦。
TripleX提到:c++标准库里有不错的算法 但是c标准库里很少。
可能这才真的是造成麻烦的根源。对于已经存在的库来说,
各种语言都有可能是很方便的,不过C/C++都没有提供太多
可用的东西,大量的库都是来源于不同的地方。对于python
来说,也是这样的,如果没有相应的库,独立设计算法,
也并不是轻松的事情。

说了这么多,其实就是希望大家不要对各种语言的效率有所
误解。也没必要刻意排斥某种语言。在合适的地方使用合适
的工具,达到咱们的目的才是最重要的。某种语言有优点,
或者缺点,咱们就去研究研究,学到了东西那就是咱自己的
财富。
2006-04-02 10:51 | dwbclz

# re: 一段Python程序和C程序的对比


假如我没记错的话,STLPORT缺省用的是pool allocator,linux下的GCC好像是pool allocator+node allocator,vc的是在crt里面维护了一个小内存池,我不知道glibc中的alloc是否也有这样的一个小内存池。

std::string:stlport和vc的都不是引用计数,但mingw和linux下的gcc似乎都是。

stream输入输出的效率极为可怕,有人测试的结果最差的是比C的3,4倍,虽然从理论上说他应该比C的要快(因为类型在编译的时候就知道了)

上面还有人说C++比python简洁.......我现在还没有找到这种感觉。我感觉C++比C更烦锁,有时候感觉到简洁是因为有些强大的类库在后面。

做大部分事情的时候,C++都不是最好的选择。stl可能更不是。C++本身效率是可以跟C一样,但这是建立在没有类型检查,没有异常,不用标准库和一个C++高手的基础上的,这种 接近真空的情况很少会出现。
2006-04-02 11:22 | sevencat

# re: 一段Python程序和C程序的对比

Re sevencat 

C++是什么?
是增强的C?是面向对象的C?是泛型的C?
或许都是,但是并不仅仅是。

C++之父说,C++是一个通用的程序设计语言。
这个通用性意味着多种方式综合使用。效率
是怎么来的?并不是你使用了C++编译器,
效率就会降低;并不是你使用了STL,效率就
会变差。效率取决于你对你所使用的工具了解
多少,取决于你使用的方法好不好。很多使用
C的人也不见得了解效率究竟耗费在什么地方,
实际测试是最好的验证办法。

“感觉到简洁是因为有些强大的类库在后面”,
这句话没错啊,任何语言不都是这样的吗?对于
Python等脚本来说也是如此,没有库,任何人都
是很为难的。至于有了库,使用的简易程度如何,
C++一定是不弱于C的,尤其是对于一些常用容器
的封装。

偏执于C或者C++都是没有必要的。很多使用C++
的人也都是按照C风格来编写代码的。适度使用
一些C++的高级特性,可以改善C的某些不足,使
得代码更容易维护,在某些情况下,效率会更高。
研究C++的某些特性,并不意味着非要滥用那些
特性。觉得不适用于某些项目的话,可以不用,
那些特性也不会有什么负面影响的。比如string
的拷贝效率比较差,大家可以不用,但是没必要
连set/map这类容器也排斥,C的map实现其实不
可能快过C++,生成的代码较少倒是真的。

上面的所谓简洁的C++代码仅仅是就“简洁”二字
来编写的,并不是说实际应用也要如此。深入的
讨论,目的是为了更好的理解。就好像我们平时负
重跑一样,比赛的时候当然不会负重了。高级特性
使用到什么程度,要看项目需求,完全地排斥
似乎没有必要的。

“做大部分事情的时候,C++都不是最好的选择”
这句话似乎有悖于现实。就目前我所知道的情况
看来,如果说C++与C相比有什么缺点的话,那就
是移植性,毫无疑问,C语言的代码有可能跑在更
多的平台上。除此之外,还有什么劣势?

HL2的代码是用C++写的,没见到有什么不对头的
地方。文明4的代码也是用C++来写的(它用了Python
应该算是C/C++/Python的混合体)。好像sourceforge
上C++项目比C的要多。语言的存在都有其独特的优势,
合理使用才会更省力,更有效率。很多项目都是会
综合使用多种方法的,多种方法本来是可以相互辅助的,
为何定要偏执某一种?
2006-04-02 12:31 | dwbclz

# re: 一段Python程序和C程序的对比

并不是你使用了C++编译器, 
效率就会降低;并不是你使用了STL,效率就 
会变差。效率取决于你对你所使用的工具了解 
多少,取决于你使用的方法好不好。很多使用 
C的人也不见得了解效率究竟耗费在什么地方, 
实际测试是最好的验证办法。 

//=======================================
虽然不一定,但大部分情况下是这样,
使用C更接近底层,所以一般人还是比较清楚效率在什么地方,
而使用C++大多不知不觉得就用了一些STL或者其他你自己都不知道内部实现的东东,就像std::string的各种实现一样,根本无从知晓。



很多使用C++ 
的人也都是按照C风格来编写代码的。适度使用 
一些C++的高级特性,可以改善C的某些不足,使 
得代码更容易维护,在某些情况下,效率会更高。 
//==================================
这些我都没有反对啊。你自己也说是“某些情况下”效率会更高。


但是没必要 
连set/map这类容器也排斥,C的map实现其实不 
可能快过C++,生成的代码较少倒是真的。
//==================================
我并没有排斥啊,事实上我自己也经常用啊,只不过效率要求高的地方用得比较小心一些。
C的map实现不可能快过C++,我想这个还是由C的核心使用者来说明吧。

C++和脚本语言的简洁我不想再说了,要完成一件事情,用脚本完成和用C++来完成,我想大部分人心里都有数的。

最后,你提到了两款C++,全是游戏,在某些行业(游戏,GUI),的确是C++占主导地位,我也从来没说过C++在所有的领域里都不行了呀,我想你是误会了。我只不过说在很多地方,用C++是不明智的,就像楼主的这种情况,写python脚本和写C++的时间比比看,当然你可以去用C++,没人拦你。
2006-04-02 14:14 | sevencat

# re: 一段Python程序和C程序的对比

您最初说的“做大部分事情的时候,C++都不是最好的选择”,
后来又修正成为“在很多地方,用C++是不明智的”。
后者我是完全同意的,前者嘛,可能是表述的问题。

本来最初发帖的目的是为了消除“C/C++”低效的误解,没成想
还有关于C++是否应该使用的问题,还有C++跟C的比较的问题。
C++是多种方法的结合体,并不是说非要STL,非要COM什么的。
您也说了“自己也经常用(set/map)”的,本来综合某些东西的
优点来合理的使用,才是C++的本意。C++可不是逼着人非要用其
高级特性的语言,C++之父说过,如果不满意标准库,完全可以自
己重新设计,C++不会在语言级给与限制。我见过的许多大的开源
项目都是接近于C风格的C++。其实不太明白,为什么要抱怨C++,
复杂性当然是有的,但是这并没有强加给任何人啊,多数的东西
都留下了选择的余地。

“C的map实现不可能快过C++,我想这个还是由C的核心使用者
来说明吧”,这个是很明显的,尤其是对于一些简单类型。C的回调
方式显然是很影响效率的。其实我不是很清楚为什么这种问题需要
由“核心使用者”来说明?“核心使用者”是哪一类人呢?

“写python脚本和写C++的时间比比看,当然你可以去用C++,没
人拦你”,这句话是写给我看的吗?我一直都在说要“综合使用多
种方法”的,可没有排斥什么。发帖的目的是为了消除“C/C++低
效”的误解,并不是为了证明C++适合用在这个题目上。
2006-04-02 15:14 | dwbclz

# re: 一段Python程序和C程序的对比

“虽然不一定,但大部分情况下是这样, 使用C更接近底层,所
以一般人还是比较清楚效率在什么地方, 而使用C++大多不知不
觉得就用了一些STL或者其他你自己都不知道内部实现的东东,就
像std::string的各种实现一样,根本无从知晓。”

事实上,很多的C和C++使用者都不会探求底层效率的差异。
事实上,很多C++使用者会自己实现一些东西,而不是完全依赖
标准库,看看那些成功的C++库便会明白这一点。STL也只不过
是众多库中的一个,STL不等于C++。

至于某些人不知不觉,那并不是C或者C++可以解决的问题,使用
C也会有很多不知不觉。关键在于使用者的目的,在各种方法之间
做选择,做平衡。C结合C++结合Script,这是很多项目模式。

再说一次啊,发帖的目的是为了消除某些误解,不是说一定要用
C++。C++有缺点,但是不能把它的优点抹去。

其实在我的概念里,C和C++在某种程度上是一样的,别人问我
用什么写程序的时候,我有时候也会简单地说“用C”。
所以,楼主提供的C程序和python的比较,让人想为C和C++说点
公道话。
2006-04-02 15:35 | dwbclz

# re: 一段Python程序和C程序的对比

今天又优化了一下昨天的那个程序,效果还是挺好的。 
所以又来唠叨两句,楼主不要撵我走,呵呵。 

为避免无谓的口水仗,首先声明啊,本文目的不在于 
证明Python不好,也不是为了证明C/C++如何。只是想 
就优化方面的东西做一些探讨。

昨天的那个程序没有做读缓存,今天用了我以前的一 
些代码,加上了读缓存。 
文件操作是对WindowsApi的直接封装,没有调用C函数。 
set容器是我根据STLport改装的,分配器优化的方式跟 
昨天的那个代码差不多。 

采用18M的那个文件做测试: 
平均时间在1140ms左右。 
昨天的那个程序是1650ms。 
python的程序大约是3.8s。 
最终版本的效率是python的三倍多。 

另外经过参数调整和比较发现,缓存的大小也要很注意 
才行,32KB~64KB的缓存似乎效果最好。读缓存的大小影 
响不是很大,写缓存太大了效果会很差。我想这种现象 
应该跟操作系统的异步IO有关。写入太多数据,就要花 
费时间阻塞,写入少量数据的话,操作系统应该会异步 
处理回写的操作。减少阻塞的时间是一个很大的原因。 

代码参见
http://blog.csdn.net/imjj/archive/2006/03/31/645163.aspx?Pending=true

别人的Blog,俺去胡闹来着。
2006-04-02 19:13 | dwbclz

# 我觉得我选vckbase是选对了

本来是随手写的一个帖子,学到了很多东西,见识了这么多各个方面的软件工程师,呵呵. 其实我本来是用C++的,不过不像各位那样深刻,而且一直没用过STL,对模版也一知半解,跟各位比起来真是惭愧. 以后在vckbase还请多指教. 
Python对我来说,其实仅仅是一个工具,看看我用它干过的事情就知道了,:)
a) 各种文件处理,如果用编辑器不能搞定,我就用Python. 其实我知道Linux下的shell可能也能处理大部分,不过Python我用得比较顺些
b) 软件原型,偶尔会用Python写一些原型来验证设计.不过用的不是很多,
毕竟和C++在语言上差别太大
c) 过年的时候写过一个程序在网上抢转让的二手车票,并且成功搞到多张回家的车票.
d) 玩ogame,给联盟写了一个小网站,用于查询星图等信息....
总而言之,我从来没打算把Python和C++/C 相提并论,我发那个帖子的原因恰恰是因为我惊讶的发现在这个例子里,Python的性能表现竟然没有比C/C++差出去一大截子.

真正搞软件,我还是用C++和OOD,不过因为水平有限,我从来不会坚定的支持某种语言或者范式, 包括软件开发流程也是,我既相信统一开发过程,也尝试过xp里的一些东西,比如测试驱动, 也许等我哪天水平真正高的了,
我也会坚定的维护某些东西 (也许那时候已经老了...)

谢谢大家..:_)
2006-04-02 22:13 | jzhang

# re: 一段Python程序和C程序的对比

to dwpclz:
你提到 "C的map实现其实不可能快过C++,生成的代码较少倒是真的. "
C标准库里有map实现吗? 我孤陋寡闻了......
2006-04-02 22:58 | TripleX

# re: 一段Python程序和C程序的对比

这里这么多c++高手 我顺便借人气问一个困扰我很久的事情
我们原来做过一个嵌入设备的web管理界面 是用C实现的
基础是一个XML-parser和一个自己实现的MVC框架 
MVC框架是一个不到50k的动态库 XML-parser也就百来k
主程序的所有module都编译成一个可执行文件 不到300k
所有的东西加起来 不到500k(不包括标准C库) 
不久以后 我帮客户做移植 他们原来的代码是c++写的 
原来在x86下运行 没太考虑大小 移植到arm下发现编译完
以后是10M !! (strip过 没strip过是50M !!) 回头看x86的二进制
文件 也是一般大 编译参数调整也没什么好转 而且似乎也没有
用什么特别的东西 他们的代码做的事情和我们的差不多 但是
实现的方式不了解 因为只是做移植的技术支持 看别人的代码
有违职业道德 不过wc看了一下 大概也就不到5万行代码
我们那个C写的代码是3万行(不包括xml-parse和mvc框架)
我想知道的是 c++有什么写法 或者什么样的设计框架 或者
是使用哪些库 会导致代码编译完以后非常庞大 我很希望能
在下一个项目里使用C++  但是我也很担心会掉到未知的陷阱里
本来有机会能搞明白那件事情的 就是把那个可执行文件反汇编
了一个一个方法看过去.... 但是别人的代码 实在不方便查看
实在太奇怪了 也见过不少c++写的opensource软件 但是没见过
二进制的尺寸和源代码规模差这么多的.....
2006-04-02 23:26 | TripleX

# re: 一段Python程序和C程序的对比

to TripleX 

提出这样的问题是不是算抬杠呢?
本来对于我来说,C/C++没有太多界限。真不想争这个。
对于我参与的项目而言,我也会使用偏重于C风格的设计。

基于RBTree的东西,还是基于Hash算法的东西,都是查找
表嘛。我说的那句话从严格性上来说当然有问题,不过不想
抬杠的人都应该可以读懂的。难道说非要把
std::hash_map与XXX库里的ChashMap相比才可以?
或者说我应该说vc7.1 stdext::hash_map?
其实只要是算法相同的,除非C抛弃了通用性,否则效率上
就是会有点问题,回调函数的损耗摆在那里的。或者说
损失可读性(使用宏?),倒是也见过有人这么做的。

只想叹口气,唉。本来只想消除一下某些误解,没想
说C++跟C比较什么。
2006-04-03 07:26 | dwbclz

# re: 一段Python程序和C程序的对比

To TripleX 
请教一下,那个项目在x86下编译有多大,在arm下编译
“hello world”有多大。俺没写过其它设备的程序,没啥
概念。

还有,strip是什么意思?可执行程序压缩?x86下可有
类似的工具?

按照x86下面的感觉,10M的可执行程序(C++),代码应该在百
万行以上,
2006-04-03 07:45 | dwbclz

# re: 一段Python程序和C程序的对比

to dwbclz:
我不是要抬杠 只是看到C也有map库 很吃惊 至于效率 
如果用宏实现 也不会差 
strip是用来去除elf文件的debug信息的 一般情况下编译
都加-g参数 方便调试 发布的时候用strip去掉debug信息
那个项目在x86下编译 比arm下小5%....   我记得我还在
OSX下编译过 还要稍微再大一些 11M左右 也就是说 在哪个
体系结构下尺寸都差不多 
hello world代码 在arm下 没strip 13k strip后 3.7k
所以我很好奇怎么写代码才能能编译出10M的二进制文件 .....
2006-04-03 10:54 | TripleX

# re: 一段Python程序和C程序的对比

可惜不能看看那个工程,我对这些奇怪现象感兴趣。
10M,至少也要百万行代码啊。见过的最大的框架
应该是VCL,编译以后也不过3,5百K。
也许它使用了什么库?用一点点xerces XML,至少也要
增重1M以上……。
2006-04-03 21:01 | dwbclz

# re: 一段Python程序和C程序的对比

据说到现在为止c++的编译器还不够好
2006-04-03 23:26 | wmuu

# re: wmuu

呵呵,可是最好的编译器都是C++的。
GCC,MSVC。

不过高级的语言有高级的效率,这一点C++似乎
还差很多。我比较过xerces XML(算是最全面的C++实现
了吧)和.Net XML(.Net2.0),Load文件的时间大约是7:5。
看过微软的开源实现(sscli),感觉很多优化的技术
不是C++语言可以做到的。当然如果硬要做,牺牲易用性
来做也不是不可以……。
2006-04-04 07:31 | dwbclz

# re: 一段Python程序和C程序的对比

g++才是c++的吧?
gcc主要是c的
2006-04-04 12:48 | wmuu

# re: 一段Python程序和C程序的对比

算了,不说了,俺还是找个地方进行技术讨论比较好。
2006-04-04 13:33 | dwbclz

# re: 一段Python程序和C程序的对比

我也凑一下热闹。780000数据集Python版在我这里运行时间大约3100ms(Python 2.4)
我写了个C#版,用Dictionary<TKey, TValue>来进行唯一化,StreamWriter, StreamReader进行IO。运行时间是810ms

2006-04-04 13:49 | Ninputer

# re: 一段Python程序和C程序的对比

C#版本如下
static void Main(string[] args)
{
    Stopwatch w = new Stopwatch();

    w.Start();

    Dictionary<string, byte> dict = new Dictionary<string, byte>(720000);
    using (StreamReader sr = new StreamReader("g:\\shared\\email\\email.txt"))
    {
        using (StreamWriter sw = new StreamWriter("g:\\shared\\email\\email_new.txt"))
        {
            while (sr.Peek() != -1)
            {
                string l = sr.ReadLine();
                if (dict.ContainsKey(l))
                {
                    sw.WriteLine(l);
                }
                else
                {
                    dict.Add(l, 0);
                }
            }
        }
    }

    w.Stop();

    Console.WriteLine(w.ElapsedMilliseconds);
}
2006-04-04 13:58 | Ninputer

# hehe, C# 也登台了

我想
Dictionary<string, byte> dict = new Dictionary<string, byte>(720000);
预分配是不是起了很大的作用?
Python没办法郁分配
2006-04-04 14:04 | jzhang

# re: 一段Python程序和C程序的对比

实际上可能主要归功于.NET的String散列函数非常好,而且Dictionary所用的hashtable算法也较好。当然预分配的作用也是比较明显的,不预分配的版本,时间为1103ms
2006-04-04 14:07 | Ninputer

# re: 一段Python程序和C程序的对比

啊啊对不起,好像写错了
把重复掉的都给写进结果文件了
2006-04-04 14:17 | Ninputer

# re: 一段Python程序和C程序的对比

重测了一遍,是1500ms
2006-04-04 14:24 | Ninputer

# hehe,我也没看出来

你的程序把重复的写入文件,不重复的反倒没写...hoho
不过修改后的1500ms还是很快。:)
2006-04-04 14:31 | jzhang

# re: 一段Python程序和C程序的对比

在不同的机器上测试了一下性能 用的上面那个c代码的版本
不过把hash size改大了 测试文件用的是780,000行的大文件

首先用的是一台PIII 1.13G, 512M SDRAM, 7200rpm IDE Disk
root@dual:~/mytest/eml# time ./eml email.txt b
real    0m1.319s
user    0m1.038s
sys     0m0.281s

然后在一个Xeron 2.8G, 2G DDR, 10000rpm SCSI Disk, RAID 0
bjm2:/mnt/cache/eml# time ./eml email.txt b
real    0m0.706s
user    0m0.592s
sys     0m0.114s
发现这个代码用icc编译的版本速度和gcc相当 不象openssl那样
用icc编译比gcc快很多 IO应该都cache住了 因为sys time非常低
所以我疑心是malloc的问题 prof了一下 发现消耗cpu最多的函数
居然是hash_string 就是用从char *算hash key的函数 呵呵
用rb-tree的cpp版本 运行时间分别是
PIII
root@dual:~/mytest/eml# time ./eml1 email.txt b
real    0m10.163s
user    0m7.799s
sys     0m2.362s

Xeron
bjm2:/mnt/cache/eml# time ./eml1 email.txt b
real    0m9.863s
user    0m5.208s
sys     0m4.649s
PIII 1.13G居然不比Xeron 2.8G快多少 不知道为什么c++的版本
会比c的版本sys time高这么多 python和perl的版本 虽然
user time高不少 但是sys time和c的版本是持平的 毕竟IO的量是相当的
Xeron
bjm2:/mnt/cache/eml# time python eml.py
2006-04-04 20:47:51.829037
2006-04-04 20:47:54.662438
real    0m3.306s
user    0m3.137s
sys     0m0.171s

Xeron
bjm2:/mnt/cache/eml# time perl eml.pl
real    0m2.993s
user    0m2.665s
sys     0m0.216s
有没有c++高手能告诉我原因是什么 .....
hash_set的版本跑不起来 .... segment fault 
那个c++编译完很大 原因找到了 c也有同样的问题 
比如这么一个c程序 用gcc编译一下....

unsigned long vec[1024*1024];
int main(int argc, char **argv)
{
     int i;
     for(i=0; i< 1024*1024; i++) {
         vec[i] = 1;
     }
     return 0;
}
2006-04-04 20:56 | TripleX

# re: 一段Python程序和C程序的对比

在不同的机器上测试了一下性能 用的上面那个c代码的版本
不过把hash size改大了 测试文件用的是780,000行的大文件

首先用的是一台PIII 1.13G, 512M SDRAM, 7200rpm IDE Disk
root@dual:~/mytest/eml# time ./eml email.txt b
real    0m1.319s
user    0m1.038s
sys     0m0.281s

然后在一个Xeron 2.8G, 2G DDR, 10000rpm SCSI Disk, RAID 0
bjm2:/mnt/cache/eml# time ./eml email.txt b
real    0m0.706s
user    0m0.592s
sys     0m0.114s
发现这个代码用icc编译的版本速度和gcc相当 不象openssl那样
用icc编译比gcc快很多 IO应该都cache住了 因为sys time非常低
所以我疑心是malloc的问题 prof了一下 发现消耗cpu最多的函数
居然是hash_string 就是用从char *算hash key的函数 呵呵
用rb-tree的cpp版本 运行时间分别是
PIII
root@dual:~/mytest/eml# time ./eml1 email.txt b
real    0m10.163s
user    0m7.799s
sys     0m2.362s

Xeron
bjm2:/mnt/cache/eml# time ./eml1 email.txt b
real    0m9.863s
user    0m5.208s
sys     0m4.649s
PIII 1.13G居然不比Xeron 2.8G快多少 不知道为什么c++的版本
会比c的版本sys time高这么多 python和perl的版本 虽然
user time高不少 但是sys time和c的版本是持平的 毕竟IO的量是相当的
Xeron
bjm2:/mnt/cache/eml# time python eml.py
2006-04-04 20:47:51.829037
2006-04-04 20:47:54.662438
real    0m3.306s
user    0m3.137s
sys     0m0.171s

Xeron
bjm2:/mnt/cache/eml# time perl eml.pl
real    0m2.993s
user    0m2.665s
sys     0m0.216s
有没有c++高手能告诉我原因是什么 .....
hash_set的版本跑不起来 .... segment fault 
那个c++编译完很大 原因找到了 c也有同样的问题 
比如这么一个c程序 用gcc编译一下....

unsigned long vec[1024*1024];
int main(int argc, char **argv)
{
     int i;
     for(i=0; i< 1024*1024; i++) {
         vec[i] = 1;
     }
     return 0;
}
2006-04-04 20:57 | TripleX

# re: 一段Python程序和C程序的对比

有意思,我的理解应该有误。但是很奇怪啊。算HASH_VALUE的算法应该也是:
inline size_t
__stl_hash_string(const char* __s)
{
unsigned long __h = 0;
for ( ; *__s; ++__s)
__h = 5*__h + *__s;
return size_t(__h);
}
的吧?不知道预先定义好长度会不会快些。
2006-04-05 08:36 | sevencat

# re: 一段Python程序和C程序的对比

To TripleX :
C++下大量使用 模板,宏定义, 可以大大简化程序码,反过来说,看起来程序码不多,编译出来的目标文件可能相当大。


2006-04-05 21:55 | tongshou

# TripleX,你的那个程序编译后大小正常啊

gcc for cygwin 编译的结果 大概12k.
修改数组的大小也一样。是不是编译器优化选项的问题?
某些编译器把循环赋值给展开了?
2006-04-06 09:08 | jzhang

# 不好意思 代码写错了一点点

应该是这样的 :-)

unsigned long vec[1024*1024] = {0};
int main(int argc, char **argv)
{
     int i;
     for(i=0; i< 1024*1024; i++) {
         vec[i] = 1;
     }
     return 0;
}
2006-04-06 18:41 | TripleX

# 一个Python程序引发的讨论[TrackBack]

一篇题为“为何Python这么快”的文章登上了CSDN首页,引起了很多人注意。本文借此探讨一些C/C 的优化方法。

蒋黎引用了该文章,地址:http://blog.csdn.net/dwbclz/archive/2006/04/06/653294.aspx
2006-04-06 19:57 | 蒋黎

# re: 一段Python程序和C程序的对比

再贴一个好玩的 用mono跑c#版本的程序 在上面的那个Xeron机器上
和python的速度差不多 因为Stopwatch在mono下没法用 所以我
用time命令测试时间 连vm启动的时间也算上了 这点上对比python
和perl也算公平  而且这个时间应该很短 (至少对python和perl如此)
运行的时间和python差不多 看来mono还需要很多优化 
另外 sys time很短 我还是很奇怪c++写的版本(用set和fstream的版本)
sys time为什么会那么高  按说IO的数量应该是一样的阿

bjm2:/mnt/cache/eml# time mono eml.exe 
real    0m3.463s
user    0m3.346s
sys     0m0.118s
2006-04-06 21:22 | TripleX

# re: 一段Python程序和C程序的对比

strace了一下 原因应该是这样的 这个是C版本的trace结果
.....
read(3, "cn\r\njason764663@sina.com.cn\r\njas"..., 131072) = 131072
write(4, "ina.com.cn\r\njason759130@sina.com"..., 131072) = 131072
brk(0xabf8000)                          = 0xabf8000
brk(0xac19000)                          = 0xac19000
read(3, "om.cn\r\njason769906@sina.com.cn\r\n"..., 131072) = 131072
write(4, "4@sina.com.cn\r\njason764855@sina."..., 131072) = 131072
.....
C的版本用的是fwrite  默认的buffer居然是128k ......
c++直接用IO流   outfile << str << endl; 输出
trace的结果是
.....
write(4, "jason1640@sina.com.cn\r\n", 23) = 23
write(4, "jason1641@sina.com.cn\r\n", 23) = 23
write(4, "jason1642@sina.com.cn\r\n", 23) = 23
write(4, "jason1643@sina.com.cn\r\n", 23) = 23
.....
居然是没有buffer的 每次写23个字节..... 虽然内核有cache 但是
增加的上下文切换的次数也很多了... c++默认的IO流是无buffer的么?
2006-04-06 21:32 | TripleX

# re: 一段Python程序和C程序的对比

outfile << str << endl; endl好像默认会刷新缓存
2006-04-06 23:00 | wmuu

# re: 一段Python程序和C程序的对比

改成outfile<<str<<"\n"会好很多
2006-04-06 23:01 | wmuu

# re: 一段Python程序和C程序的对比

提高了不少 :-)
bjm2:/mnt/cache/eml# time ./eml1 email.txt b
real    0m3.694s
user    0m3.515s
sys     0m0.179s
2006-04-06 23:12 | TripleX

# re: 一段Python程序和C程序的对比

c++里头还有一个streambuf的类,这位大侠是不是再。。。
嘿嘿

自己不想试:)
2006-04-06 23:29 | wmuu

# re: 一段Python程序和C程序的对比

顺便把输入输出都buf一下:)
2006-04-06 23:32 | wmuu

# re: 一段Python程序和C程序的对比

晕倒,题外话,
对别人的Blog链接会自动添加回帖吗?
2006-04-07 07:27 | dwbclz

# re: 一段Python程序和C程序的对比

今天早晨,TripleX的回帖让我想到一种优化方式,于是把我的
程序又改了一下,去掉了C库的读写缓存,效率有微量提高。 
setvbuf(m_file, 0, _IONBF, 0); 
这个函数对于写操作提升较多,对于读操作收获较小。

我也开Blog了,有空去看看? 
http://blog.csdn.net/dwbclz/
2006-04-07 07:45 | dwbclz

# re: 一段Python程序和C程序的对比

想到一点,Python的程序和C++有一点不同,在于set/map的实现。
STL的容器可以根据返回值判断对象是否存在,Python似乎不能。
所以python每个循环实际上判断了两次,一次判断是否存在,一次
是插入对象的时候。
那个C#程序在我这里执行时间是2500ms,它也存在多次判断的问
题。
2006-04-07 07:49 | dwbclz

# re: 一段Python程序和C程序的对比

前些天下载了xerces-c 2.7.0,感觉效率有所提高,但是
还是没有.net2.0的xml快(差了10%以上)。.net的优化
确实不是吹出来。让人很佩服。
不过.net2.0虽然执行代码快,但是总体效率似乎不太好。
可能是占用内存太多了,或者微软的程序设计了太多的
功能。
2006-04-07 08:21 | dwbclz

# re: 一段Python程序和C程序的对比

vc7.1下,自己写了一个hash_compare的类,用了java的string的hash算法。

void testmail(){
ifstream infile;
ofstream outfile;

hash_set<char*,my_str_hash_compare> ht;
int bufsize = 100;

infile.open(IN_FILE_NAME);
outfile.open(OUT_FILE_NAME);

char* buf = new char[bufsize];
if(buf == NULL){
exit(1);
}
while(infile.getline(buf, bufsize)){
if(!(ht.insert(buf)).second){
continue;
}
outfile<<buf<<"\n";
buf = new char[bufsize];
if(buf == NULL){
exit(1);
}
}

hash_set<char*,my_str_hash_compare>::iterator iter = ht.begin();
hash_set<char*,my_str_hash_compare>::iterator end = ht.end();
for(;iter!=end;++iter){
delete[] *iter;
}

return;
}

class my_str_hash_compare
{ // traits class for hash containers
public:
enum
{ // parameters for hash table
bucket_size = 4, // 0 < bucket_size
min_buckets = 8}; // min_buckets = 2 ^^ N, 0 < N

my_str_hash_compare()
{ // construct with default comparator
}

size_t operator()(const char* _Keyval) const
{ // hash _Keyval to size_t value
return ((size_t)hash_code(_Keyval));
}

bool operator()(const char*_Keyval1, const char*_Keyval2) const
{ // test if _Keyval1 ordered before _Keyval2
return strcmp(_Keyval1,_Keyval2) < 0;
}

};

int hash_code(const char* p){
int hash =0;
while(*p){
hash= 31*hash+*(p++);
}
return hash;
}

结果是
E:\c\mail\Release>mail
c++
经过了3765.6250毫秒
经过了3921.8750毫秒
经过了3890.6250毫秒
经过了3937.5000毫秒
经过了3937.5000毫秒
经过了3921.8750毫秒
python
4125.0
4108.99996758
4046.00000381
4062.99996376
4062.00003624
4046.99993134

只比python快一点
2006-04-08 01:18 | wmuu

# re: 一段Python程序和C程序的对比

写了一个mmap的版本 C代码 还用了预分配 比原来的C代码快了一倍 
无论是在G4还是在Xeron上
iBook G4 800MHz上的结果 eml是原来用标准IO的版本 eml-mmap是用mmap的版本
Zhong-Yus-Computer:~/mytest/eml zhongyu$ time ./eml email.txt b
real    0m3.256s
user    0m1.930s
sys     0m1.060s
Zhong-Yus-Computer:~/mytest/eml zhongyu$ time ./eml-mmap email.txt b
real    0m1.300s
user    0m0.870s
sys     0m0.270s
在Xeron 2.8GHz上的结果 
bjm2:/mnt/cache/eml# time ./eml email.txt b
real    0m0.702s
user    0m0.575s
sys     0m0.127s
bjm2:/mnt/cache/eml# time ./eml-mmap email.txt b
real    0m0.348s
user    0m0.321s
sys     0m0.027s
mmap的好处就是减少了user/kernel之间内存拷贝和上下文切换
再结合预分配 能节省不少cpu的开销 
2006-04-09 12:46 | TripleX

# re: 一段Python程序和C程序的对比

比相同机器上运行的python代码 还是快了10倍
这个是同样在xeron2.8GHz上运行的python代码的结果
bjm2:/mnt/cache/eml# time python eml.py
2006-04-09 12:47:00.356185
2006-04-09 12:47:03.451726
real    0m3.597s
user    0m3.347s
sys     0m0.212s
3.5s vs 0.35s 不过C代码需要用很多低层的优化手法
比如mmap 还有hard code的hash_size 预分配等等
写起来比较累 也没有python代码这么直观
2006-04-09 13:00 | TripleX

# re: 一段Python程序和C程序的对比

能否提供代码?10倍的那个?
2006-04-10 07:57 | dwbclz

# re: 一段Python程序和C程序的对比

内容太长 没法贴....
2006-04-10 08:46 | TripleX

# re: 一段Python程序和C程序的对比

放在server上了 
http://bjm2.server.18mail.cn/eml.tgz
包含测试数据 有点大 包含如下文件
eml.c   最初的c版本 用标准io 
eml-mmap.c  mmap版本
eml.py  python版本
eml.pl   perl版本
eml.cs  c#版本
eml1.cpp  c++版本 用<set>
eml2.cpp  c++版本 用<hash_set>
编译参数在x86上都是-O3 -fomit-frame-pointer
2006-04-10 10:06 | TripleX

# re: 一段Python程序和C程序的对比

放在server上了 
http://bjm2.server.18mail.cn/eml.tgz
包含测试数据 有点大 包含如下文件
eml.c   最初的c版本 用标准io 
eml-mmap.c  mmap版本
eml.py  python版本
eml.pl   perl版本
eml.cs  c#版本
eml1.cpp  c++版本 用<set>
eml2.cpp  c++版本 用<hash_set>
编译参数在x86上都是-O3 -fomit-frame-pointer
email.txt是源数据文件  b是生成的数据文件
2006-04-10 10:07 | TripleX

# re: 一段Python程序和C程序的对比


事实上这里的比较,很突出是算法上的比较,虽然解释型语言的程序运行时,在解释程序码过程需要花费一些时间,但是解释型语言的程序码往往比较简短,可以缩短解释花费时间,除了“解释”开销外,解释型语言调用的内部预定义的功能块, 属于编译型,也就是说,那些功能块也是用C/C++编写和编译的。这里的差异已经不是语言方面,而是算法方面了!因此笼统说 解释型语言 比C/C++慢、或快,都是不准确的。

作为解释型语言,如何扬长避短,提供高效率、高集成功能,非常重要。
2006-04-25 21:24 | ishou

# re: 一段Python程序和C程序的对比

用python的优化模块psyco试试,时间减少至原来的二分之一。

#remove duplicated email address from file
import psyco
psyco.full()
import time

def gogo():
t = time.time()
hashtable = {}
f = file("email.txt","r")
f2 = file("email_new.txt","w")
line = f.readline();
while len(line)>0:
if not hashtable.has_key(line): 
hashtable[line] = 1
f2.write(line)
line = f.readline();
f.close()
f2.close()
t2 = time.time()
print t2-t

if __name__ == "__main__":
gogo()
s=raw_input()
2006-06-04 03:29 | fxsjy

# re: 一段Python程序和C程序的对比

不是python有多么快,而是这个比较的c++程序写得太差,拿这么差的程序来跟python的hash算法比较可想而知结果是什么。在我的机器上我用我的hash表测试了一下,结果如下:

c++/hash     我自己实现的hash表     93 毫秒
python          原作者给出的程序        250毫秒

2006-06-07 08:54 | arcnode

# re: 一段Python程序和C程序的对比

补充一下,原来的emil.txt 78000行, 但有效email个数是77999条,最后是一个空行。
2006-06-07 08:58 | arcnode

# re: 一段Python程序和C程序的对比

在windows平台下用vc6.0 匆忙试验了一下,
只成功编译了TripleX 的eml1.cpp,另外用原作者的py文件测试了一下,还有我自己写了一段程序处理(文件处理用最普通的FILE,fgets...),三者结果如下:

eml1.cpp                 484 毫秒
python                      250毫秒
我的测试程序     93毫秒

不知道有没有什么参考价值。

我的机器:
P4 3.0G/512M/120G硬盘


期待有人能在windows把Triplex的几个算法全部改写成能编译的进行比较。

2006-06-07 09:21 | arcnode

# re: 一段Python程序和C程序的对比

特别说一点,有很多人用<set> <hash_set>,请使用这些的人看清楚,<set> <hash_set>都是大小写敏感的,email地址应该是大小写非敏感的,功能都没有完全实现的情况下比较速度我看很可笑。我的测试程序是处理了大小写敏感问题的。
2006-06-07 11:37 | arcnode

# re: 一段Python程序和C程序的对比

从3.28开帖到现在居然没有人发现众多程序都是错误的,根本没有处理大小写敏感问题,真是可笑,还讨论得这么热乎。更可笑的是有的人不首先考虑算法问题而是优先考虑输入输出接口,考虑如何通过内存映射文件节省时间,为的就是在执行时间上优于别人的方法,真不知道你们算法怎么学的,优化怎么学的。

还看到有的人鄙视python的第一句话就是“python的特点就是慢”,我真为你感到汗颜,一方面你根本不知道程序速度是哪些原因决定的,python并不是慢的代名词,c也不是快的代名词,通过这个例子你们也看到,c写的垃圾代码比python慢了不止一点点。另方面也鄙视你们不懂应用,真正的应用环境中并不总是需要最高速度,实际上很多时候速度都不是问题,开发快速维护简单是软件的最基本要求,否则什么都为了最快就不要开发别的语言了,大家都用汇编和c/c++吧。还要delphi, vb, php, asp等干什么。


2006-06-07 21:33 | arcnode

# to arcnode

我还是第一次知道psyco,谢谢你的留言,有时间我得看看。
其实优化是我的弱项,因为基本上都工作在应用层面,只有
少数几次优化的经历。我非常赞同优化的重点在算法上,不过前面
提出的很多优化的方法也是非常有见地的。
至于email大小写的问题,你说得对,我开始的程序就没有考虑到,
导致后面大家也都按照这个来了,呵呵。惭愧。
2006-06-07 22:13 | jzhang

# re: 一段Python程序和C程序的对比

看世界杯间隙改了些编译选项又测试了一下,发现用7.8万行数据的时候最快只要78毫秒处理完,当把数据增多到78万行(10倍)的时候最短处理时间是487毫秒。我用vc2005也编译了一把,发现处理78万行数据的时候最短处理时间是515毫秒,比vc6编译结果还要稍微慢一点,比较失望,原指望它更快的。(开了多个优化选项)

同条件下对比速度(处理7.8万行):
eml1.cpp                 484 毫秒  (多次最短时间)
python                      250毫秒   (多次最短时间)

我的机器: 
P4 3.0G/512M/120G硬盘 
2006-06-10 00:58 | arcnode

# re: 一段Python程序和C程序的对比

winxp下用文件映射处理了一把,输出仍然是用fopen, fwrite等,现在全部处理时间是328毫秒。
2006-06-10 01:37 | arcnode

# re: 一段Python程序和C程序的对比

请教各位大侠们个问题,你们的运行时间怎么计算的?
谢谢了
2006-06-11 11:25 | 小白

# to 小白

不同的语言都会有获取系统时间的函数,在开始处理前取得当前时间,处理结束后再取一次,两者的差就是运行时间了。在Linux下的用户可以使用time 命令来计算运行时间,可以得到更加精确的信息。
2006-06-15 11:28 | jzhang

# re: 一段Python程序和C程序的对比

from datetime import datetime
begin = datetime.now()

ifile = file("in.txt", "r")
ofile = file("out.txt", "w")

ofile.write(''.join(set(ifile)))
    
ifile.close()
ofile.close()

t = datetime.now() - begin
print "Total time is %s.%s seconds." % (t.seconds, t.microseconds)

呵呵,一直努力学习ASM/C/C++, 前天看到这个帖子,用C++测试了一下(使用std::vector<char*>, 配合std::sort()),速度在1秒左右.看着上面讨论这么激烈,而且一直想学一门脚本语言,于是昨天安装上python2.4,看了大半天入门教程,试着写了上面的python版, 速度在1.2秒左右.真是令我惊奇不已,一下子就喜欢上了python,特别是不同于C/C++的那些新奇的语法.
2006-06-15 19:25 | PyBeginner

# re: 一段Python程序和C程序的对比

dwbclz说我的代码中unique_copy有问题,但是你没有注意到前面一句sort吗?

还有,说C++代码复杂的,我的代码和python的代码都在上面,自己对比一下吧。优化的另当别论。我不是否定Python,但是Python的长处显然不是在性能上。

另外,这个程序最大的瓶颈就是文件IO,凭什么得出Python快的结论?C++完全可以在语言范围内达到极高的性能,Python能在本语言范围内改进多少?
2006-07-19 11:30 | 非典型秃子

# 这个话题被转载了无数的地方,每个地方都有人像你这么说

:)。 我,以及很多后来转载,扩展的人的观点都是:
Python是个好东西。
仅此而已,为什么拿C/C++来作比较,那是因为,我们都相信C/C++毫无疑问在性能是一个非常好的东西,我们因为Python能够接近C/C++的性能,同时保持强大的简单性而感到高兴。
我也不希望有人看到这个话题之后,不学C/C++,那样是他们的损失。
2006-07-19 14:38 | jzhang

# 一个hash_map使用错误[TrackBack]

一个hash_map使用错误.

g 的 hash_map 运行不起来.

金庆引用了该文章,地址:http://blog.csdn.net/jq0123/archive/2006/07/20/947948.aspx
2006-07-20 16:40 | 金庆

# re: 一段Python程序和C程序的对比

/tmp> random-ip 1000000 > /tmp/ips
/tmp> wc ips
 1000000 1000000 14281153 ips
/tmp> ls -lah ips
-rw-r--r--  1 victor  wheel    14M Aug 29 18:09 ips
/tmp> time sort -fu ips > got.txt
2.008u 0.094s 0:02.13 98.1%     61+336356k 0+108io 0pf+0w

一百万个随机IP,排序,不区分大小写(虽然没用)

下面是一千万个随机ip
 /tmp> random-ip 10000000 > /tmp/ips
 /tmp> time sort -fu ips > got.txt
28.416u 1.453s 0:30.37 98.3%    61+292302k 6+2182io 0pf+0w
 /tmp> ls -lah ips
-rw-r--r--  1 victor  wheel   136M Aug 29 18:13 ips

sata盘,测试时io负载比较重。 

关键是我比机器贵,写这个shell几秒钟。用perl写得一分钟,还要开vi。  有多这些时间可以先写shell,喝茶。 看不对了,再写程序不迟。
真是很大的任务可以 
sort -fu ips > got.txt ; echo "subject: ok" | /usr/sinb/sendmail -t me@some
然后回家睡觉。

这个问题很大程度是在确定平台下如何优化排序的问题。 没有什么代表性。 

我再提一个问题 。SATA硬盘, 512M内存, 100G随机ip,\n分割格式,近似每1G一个文件。 去重到另外一组文件,文件名为序列号,每个结果文件不超过1G。 注意源文件之间重复的也要去重。  

 
2006-08-29 18:31 | Victor Lue

# re: 一段Python程序和C程序的对比

直接开辟256M内存 用位来确定一个ip是否出现 一次可以派2GIP
两次就ok
2007-02-06 19:02 | ...

# re: 一段Python程序和C程序的对比

哈哈没,真热闹阿~ 我加一个Delphi的吧
procedure TForm1.Button1Click(Sender: TObject);
var
  List: TStringList;
  I: Integer;
  a: TDateTime;
begin
  List := TStringList.Create;

  a := Now;
  List.LoadFromFile('email.txt');
  List.Sort;

  I := 1;
  while I <= (List.Count - 1) do
    if List[I] = List[I - 1] then
      List.Delete(I)
    else
      Inc(I);

  List.SaveToFile('aa.txt');
  a := Now - a;
  ShowMessage(FloatToStr(a * 60 * 60 * 24));
  List.Free;
end;

没有使用任何优化算法,通过一个TStringList类处理
时间显示  750ms左右

2007-02-07 15:08 | J

# re: 一段Python程序和C程序的对比

"很难想象吧,Python在这里的性能竟然跟C不相上下!而且Python的代码比C不知道短了多少倍!
所以讲,Python是蛮好用的,:-). "


看过搞笑的也没看过这么搞笑的,python调和的是C写好的库,代码不少点还混什么。至于速度,用C来解释脚本,再调用C库会比C代码快,我也服了你了。如果想用C做对比的测试例子,麻烦直接用python调用的那个库相同的算法行不。
上面的情况我没实际测试,不多说,数值计算我测试过C比python快15-20倍
2007-03-19 02:28 | 不想说

# re: 一段Python程序和C程序的对比

也请争论的时候稍微学习一下什么叫脚本语言,再理解一下什么叫动态语言,然后想想哪些东西会带来开销。

对比测试是好事,可乱用例子就是坏事了
2007-03-19 02:30 | 不想说

# to 不想说

从绝对意义上来说,c当然比Python快的多。asm比c还要快一点。不过我们讨论的是一般的情况,我觉得前面的讨论结论 已经很清楚了,那就是,Python可以让人更容易的写出性能不错,又简单的程序。而C如果用的不好,反而不如Python。

你觉得呢?

2007-03-19 09:04 | jzhang

# re: 一段Python程序和C程序的对比

[code]
hash_map<string,int> a;
a["abc"] = 1; // 这一句一执行的话,程序直接退出
[/code]

if a hash_map do not have a key. a key lookup will cause an exception.
you can use 
find and insert.

# re: 一段Python程序和C程序的对比

Python可以让人更容易的写出性能不错,又简单的程序。而C如果用的不好,反而不如Python

严重同意!
http://www.dell86.org.cn/
2007-06-25 23:36 | DELL

# re: 一段Python程序和C程序的对比

不知道如何说我的感受。
这样比较有什么意义呢?楼主用python快,用c++慢,只能说明c++水平不高。不是语言的问题。
对于低水平人员来说,python开发会快很多。对于高手来说,其实都是一样的,速度一样快。
唉,不说了。我都快成无聊的人了。
2007-07-31 21:37 | xxx

# re: 一段Python程序和C程序的对比

呵呵,这贴真让我开了下眼界。

我略表达一下我的意见,那些说楼主没了解到脚本语言意义的人,我觉得你们才是没有真正了解到脚本语言的意义。

想想吧,纯以编程语言来说,最快的肯定是汇编吧,为什么了汇编还会出C?有了C还会出C++及JAVA?有了C++还出Perl,Python?是有人闲得骨头发痒,想自讨苦吃?

从以前到现在人们追求的就是一点,在性能与易用性上找到一个平衡点。没错,用熟后哪种语言都一样,不过问题是大部分人真能把一种语言用熟,或保持高度的熟练度么?大部分人的主业并不是纯写程序,程序只是工具而已,真正关注的其实是另外的问题!

象我研究数据挖掘的,主要关注的是数据的分布,概率模型等数学算法问题,用哪种语言去验正我的想法并不重要,唯一的要求就是一要好写,最好不怎么看书都能轻松写出程序,二要执行效率可以接受,不用最快,但至少不能慢个底朝天,一个算法让我等几天看结果。这种时候我绝对会选Python,上手就写,改错也容易,而且只要注意一些基本原则,效率一般不会太低。

这才是脚本语言的意义,在执行效率与易用性上给了用户一个好的平衡点。所以LZ发这贴还是很有意义的,让我们了解到在Python中一个简单的标准算法,甚至比某些情况下的C算法还要快,或差不多吧。对比一下其它长长的C代码,还有那让初学者摸不着北的C++STL代码,以后做实验就选Python了。

实际上我用Perl写了很多程序,不过Perl的语法实在让我够呛,难记,开了English模块也好不到哪儿去,尤其的面向对象这块太难看了,明显是后面强加上去的。还是Python易懂,容易组织。
2007-08-18 09:58 | A Guest

# re: 一段Python程序和C程序的对比

看了这个热贴我太晕了,性能测试有这样测的么,如果这样也行的话,那大家可以随便说汇编是最慢的;
要测性能应该基于相同的算法,而不仅仅是完成相同的功能,除非c++/c不能实现相同的算法;脚本都拿速度最快的hash,c++却拿什么set、vector(lz更是乱搞,居然拿mfc的csring);

说下我用c的测试结果把,第1个7万多行那个文件,平均70ms,第2个70万行的那个文件,平均1000ms左右;
其实lz同学的那个c代码也是hash的,只是lz非要那cygwin去跑,明明知道cygwin有性能损失还拿出来比较:(
root@bingle:~/perf-c-cpp-python$ ./rm_dup perf_email.txt
start time:1189486126.235029
end   time:1189486126.320831
total count:77999, unique count:71598

root@bingle:~/perf-c-cpp-python$ ./rm_dup perf_email2.txt
start time:1189486131.91119
end   time:1189486131.843949
total count:779999, unique count:715247
2007-09-11 12:54 | bingle

# re: 一段Python程序和C程序的对比

比啥呢?读写操作都不知道剔除,还比个P啊?
2008-07-17 01:37 | a

# re: 一段Python程序和C程序的对比

造了一个3M多行的,比较楼上各位的方法,sort -u 最快,10秒,python也是10秒+,perl17秒,秃子的版本和hash的C++基本在30s~90s
内存占用200M+
鄙视一下自以为是的C++们
D:\>wc ee
 3343517  3343517 80152619 ee
2008-07-17 03:55 | a

# re: 一段Python程序和C程序的对比

都是他妈的hash!就没有用 状态机的吗?!!你们写过/看过编译器没?编译器的符号表难道使用hash?!!hash重复了多次比较太慢了!hash不是这样用的!
2008-08-22 17:50 |

# re: 一段Python程序和C程序的对比

对字符串,用那个B什么树也会比这个hash块,鄙视python
2008-08-22 17:54 | ?????????

# re: 一段Python程序和C程序的对比

python就是垃圾
2009-06-02 16:00 | x

# re: 一段Python程序和C程序的对比

都他妈吃饱了撑得,python底层是C实现的,速度当然不会太差,比php,perl快是很正常的,
而且python比其他语言简单多了,
也支持C,
至于楼上的这种人,不懂就不要随便瞎说。
你用过python吗?会用吗?你用过其他的语言都有什么?
你把所用过的语言都比较过吗?
不要说,随便哪个语言看了两天皮毛就出来批判人家。
装逼小心被雷劈
2009-07-02 16:40 | 暗暗
标题  
姓名  
主页
验证码 *
内容   
  登录  使用高级评论  Top
[使用Ctrl+Enter键可以直接提交]