انجمن‌های فارسی اوبونتو

لطفاً به انجمن‌ها وارد شده و یا جهت ورود ثبت‌نام نمائید

لطفاً جهت ورود نام کاربری و رمز عبورتان را وارد نمائید

نویسنده موضوع: تفاوت باور نکردنی سرعت پایتون با سی پلاس پلاس  (دفعات بازدید: 11196 بار)

0 کاربر و 5 مهمان درحال مشاهده موضوع.

آفلاین سالار مقدم

  • عضو کاربران ایرانی اوبونتو
  • *
  • ارسال: 2074
  • جنسیت : پسر
  • هر چقدر بدونی بازم کمه.
    • سالار مقدم
سلام دوستان
خوب مشخصه که پایتون یه زبان مفسریه و نسبت به زبان های کامپایلی کنده، من فکر می کردم تو برنامه های بزرگ کمی کندتر باشه، اما امروز یکی از دوستان خواست که ۶میلیون بار پرتاب تاس رو شبیه سازی کنم و تعداد تکرار هر عدد رو براش بشمارم، من این رو اول به زبان سی پلاس پلاس نوشتم:
#include <iostream>
#include <cstdlib>

using namespace std;

inline int rollDice(void);

int main(void) {
unsigned int seed = time(NULL);
int dice[7] = {0};
srand(seed);
for( int i = 0; i <= 6000000; i++ ) {
++dice[rollDice()];
}
for (int i = 1; i <= 6; i++) {
cout << dice[i];
cout << endl;
}
}

inline int rollDice(void) {
return 1 + rand() % 6;
}


خوب تستش کردم به ثانیه نکشید کد اجرا شد و مشکلی نداشت، کد رو به طرف دادم گفت سی پلاس پلاس بلد نیستم پایتون بده، منم با پایتون نوشتم:
#!/usr/bin/python3
import random
dice = []
def rollDice():
    return random.randrange(1, 7)
for i in range(7):
    dice.append(0)
for i in range(1, 6000000):
    dice[rollDice()] += 1
for i in range(1, 7):
    print(dice[i], " ")
خوب کد رو اجرا کردم تا ببینم درست کار می کنه یا نه، با کمال تعجب برنامه ۱۲ثانیه طول کشید تا نتیجه رو اعلام کنه! ۱۲ ثانیه برای برنامه ی به این سادگی فاجعست! برنامه فقط باید یه عدد تصادفی ایجاد کنه و به یک لیست اضافه کنه، اونوقت ۱۲ ثانیه!؟!؟
من خودم به شدت طرفدار پایتون بودم اما ... ، واقعا تفسیر یه کد انقدر اتلاف وقت داره؟ دقیقا بین کد پایتون و زبان ماشین چه اتفاقی میافته که انقدر طول میکشه؟! آیا نوشتن برنامه ی گوشی و دسکتاپ با پایتون درسته؟ آیا روشی برای تولید برنامه ی native و یا افزایش سرعت این زبان هست؟ (چقد سی/سی پلاس پلاس خداس :دی)

آفلاین امید توانا

  • Hero Member
  • *
  • ارسال: 981
  • جنسیت : پسر
من چند بار خواستم بحثی در همین زمینه راه بندازم ولی از کامیونیتی پایتون‌دوست اینجا ترسیدم که بحث شخصی بشه. من ۲۰ سال پیش وارد دانشگاه شدم و اون زمان برنامه‌نویسی مقدماتی پاسکال بود و پیشرفته سی. از همون موقع تا حالا بیش از ۱۰ زبان جدید اومده و رفته، دلفی، ویژوال بیسیک، .... ولی هنوز سی پابرجاست. هر زبانی که باینری native تولید نکنه به سرعت از بین می‌ره چون سرعت اجرا در همه جا یک عامل مهم می‌شه زود. پایتون زبان خوبیه و خوبتر از اون گرامرشه. ولی اشتباه نکنید برای یک برنامهٔ حتی متوسط هم قابل استفاده نیست. حیطهٔ‌ کارش چسبوندنه نه اپلیکیشن. اتفاقن چند روزه دارم QtQuick می‌خوندم و بهت قول می‌دم همه چیز رو تحت تاثیر قرار می‌ده و کی‌دی‌ای ۵ که بیاد (بر اساس کیوت ۵) تحول اساسی ایجاد می‌کنه. الان شما با سی پلاس پلاس و کیوت راحت می‌تونید یک کد یکسان رو بدون تغییر، برای گنو لینوکس و فری‌بیسد و ویندوز و مک و ios و اندروید و ... کمپایل کنید.

آفلاین احسان☺ -

  • Hero Member
  • *
  • ارسال: 937
  • جنسیت : پسر
  • !no power geek
بجز مبحث سرعت حجم هم هستش.
حجم برنامه هایی که با پایتون برای گوشی نوشته میشه.(اندروید رو میگم.بقیه رو ندیدم) گاهی اوقات چند برابر برنامه هایی هستش که با جاوا و sdk نوشته شده.

آفلاین !

  • High Sr. Member
  • *
  • ارسال: 586
  • جنسیت : پسر
  • Don't Panic!
    • مانیتورینگ سایت
تایید میشه.این یکی از دلایلی بود که پایتون رو برام به حاشیه برد و عطاش رو به لقاش بخشیدم :o
I just felt like running

Altern AI Directory --- GitHub

آفلاین QSBuntu

  • High Sr. Member
  • *
  • ارسال: 613
  • جنسیت : پسر
من چند بار خواستم بحثی در همین زمینه راه بندازم ولی از کامیونیتی پایتون‌دوست اینجا ترسیدم که بحث شخصی بشه. من ۲۰ سال پیش وارد دانشگاه شدم و اون زمان برنامه‌نویسی مقدماتی پاسکال بود و پیشرفته سی. از همون موقع تا حالا بیش از ۱۰ زبان جدید اومده و رفته، دلفی، ویژوال بیسیک، .... ولی هنوز سی پابرجاست. هر زبانی که باینری native تولید نکنه به سرعت از بین می‌ره چون سرعت اجرا در همه جا یک عامل مهم می‌شه زود. پایتون زبان خوبیه و خوبتر از اون گرامرشه. ولی اشتباه نکنید برای یک برنامهٔ حتی متوسط هم قابل استفاده نیست. حیطهٔ‌ کارش چسبوندنه نه اپلیکیشن. اتفاقن چند روزه دارم QtQuick می‌خوندم و بهت قول می‌دم همه چیز رو تحت تاثیر قرار می‌ده و کی‌دی‌ای ۵ که بیاد (بر اساس کیوت ۵) تحول اساسی ایجاد می‌کنه. الان شما با سی پلاس پلاس و کیوت راحت می‌تونید یک کد یکسان رو بدون تغییر، برای گنو لینوکس و فری‌بیسد و ویندوز و مک و ios و اندروید و ... کمپایل کنید.


دقیقا ...
با این نظر دیگه جایی برای نظر دادن جز تایید نمیمونه..

سی/سی پلاس پلاس جدا بین همه زبان ها خداست!!
زندگی خواهم کرد... خواهم زیست ... و میجنگم حتی اگر........................

آفلاین nixoeen

  • ناظر انجمن
  • *
  • ارسال: 4872
  • جنسیت : پسر
  • masoft قدیم
برنامه فقط باید یه عدد تصادفی ایجاد کنه
مواظب باش، یک عدد تصادفی ایجاد کردن یکی از مسائل بسیار پیچیده توی ریاضی هستش :) این که چطوری این عدد تصادفی ایجاد می‌شه، اینکه اون زبان خودش یک RNG رو توسعه داده یا اینکه از RNG سیستم‌عامل استفاده می‌کنه، اینکه اگر از RNG سیستم‌عامل استفاده می‌کنه، از dev/random/ استفاده می‌کنه یا از dev/urandom/، همه روی سرعت کار تاثیر می‌ذارند.

برای مثال، دو برنامه‌ای که نوشتی، درسته که هر دو اعداد تصادفی ایجاد می‌کنند، ولی از لحاظ توزیع فراوانی کاملا متفاوت هستند و از لحاظ ریاضی، برنامه Python خروجی درست‌تری نسبت به برنامه ++C داره. استفاده از باقیمانده به صورت مستقیم با ()rand هیچگاه پیشنهاد نمی‌شه. (اگر خواستی می‌تونم دلیلش رو توضیح بدم)

حالا بیا همون برنامه Pythonای که نوشتی رو بدون اینکه توزیع فراوانی‌ اون رو خراب کنیم، کمی تغییر بدیم. خیلی کوچولو! حالا چند ثانیه طول می‌کشه؟
#!/usr/bin/python3
import random
dice = []
def rollDice():
    return int(random.random()*6)
for i in range(6):
    dice.append(0)
for i in range(1, 6000000):
    dice[rollDice()] += 1
for i in range(6):
    print(dice[i], " ")


آفلاین سالار مقدم

  • عضو کاربران ایرانی اوبونتو
  • *
  • ارسال: 2074
  • جنسیت : پسر
  • هر چقدر بدونی بازم کمه.
    • سالار مقدم
استفاده از باقیمانده به صورت مستقیم با ()rand هیچگاه پیشنهاد نمی‌شه. (اگر خواستی می‌تونم دلیلش رو توضیح بدم)

حالا بیا همون برنامه Pythonای که نوشتی رو بدون اینکه توزیع فراوانی‌ اون رو خراب کنیم، کمی تغییر بدیم. خیلی کوچولو! حالا چند ثانیه طول می‌کشه؟
#!/usr/bin/python3
import random
dice = []
def rollDice():
    return int(random.random()*6)
for i in range(6):
    dice.append(0)
for i in range(1, 6000000):
    dice[rollDice()] += 1
for i in range(6):
    print(dice[i], " ")
هر دو مورد رو توضیح می خوام! زمان از ۱۲ به حدود ۴ کاهش پیدا کرد، تغییر تو تابع و به دنبال اون ضرب بود، تابع رندم یه عدد بین ۰ و یک خروجی میده. این تابع تو سرعت دقیقا چه تفاوتی با تابع من داره؟
چرا استفاده از باقیمانده به صورت مستقیم با ()rand  پیشنهاد نمی‌شه؟ بجاش از چی استفاده کنیم؟
پ.ن: بحث ساخت عدد تصادفی تو ریاضی جالب بود، ولی حیف اینجا جاش نیست ...

آفلاین HSN6

  • Hero Member
  • *
  • ارسال: 866
  • جنسیت : پسر
  • یک راَکتیست اسپرانتیست پایتونیست گودوئیست!
    • بلاگ شخصی
زمان رو از کی و با چی اندازه گرفتی؟
حجم یک «سلام جهان» با کیوت برای اندروید حدودا چه‌قدره؟

آفلاین سالار مقدم

  • عضو کاربران ایرانی اوبونتو
  • *
  • ارسال: 2074
  • جنسیت : پسر
  • هر چقدر بدونی بازم کمه.
    • سالار مقدم
زمان رو از کی و با چی اندازه گرفتی؟
حجم یک «سلام جهان» با کیوت برای اندروید حدودا چه‌قدره؟
با ساعت لپ تاپ (ثانیه شمارش رو فعال کردم)
خوب "Hello World" که یه رشته ی سادست تفاوتی تو سرعت دیده نمیشه، ولی در کل اگر برنامه ای مثل برنامه ی من بنویسید فرقی نمی کنه چون مهم زبانه
« آخرین ویرایش: 18 بهمن 1392، 09:30 ق‌ظ توسط سالار مقدم »

آفلاین HSN6

  • Hero Member
  • *
  • ارسال: 866
  • جنسیت : پسر
  • یک راَکتیست اسپرانتیست پایتونیست گودوئیست!
    • بلاگ شخصی
می‌خواستم بدونم زمان اجرا رو فقط اندازه گرفتی یا کامپایل رو هم حساب کردی.
حجمش رو می‌خواستم بدونم.

آفلاین Geek

  • High Hero Member
  • *
  • ارسال: 1116
  • جنسیت : پسر
  • The answer to life the universe and everything: 42
زمان رو از کی و با چی اندازه گرفتی؟
حجم یک «سلام جهان» با کیوت برای اندروید حدودا چه‌قدره؟
با ساعت لپ تاپ (ثانیه شمارش رو فعال کردم)
خوب "Hello World" که یه رشته ی سادست تفاوتی تو سرعت دیده نمیشه، ولی در کل اگر برنامه ای مثل برنامه ی من بنویسید فرقی نمی کنه چون مهم زبانه

فکر کنم راه کارهای جالب‌تری هم باشه! ;)
مثلا،قبل از حلقه ها زمان سیستم رو ثبت میکردی و بعد از آخرین حلقه هم زمان رو میگرفتی و بعد اختلاف رو چاپ میکردی!

برای مثال یه همچین حلقه ای تو سیستم من ۱۴ ثانیه طول کشید تا به انتها برسه:

import time
a = time.time()
i = 1000000
while i>1 :
        i = i - 1
        print i
b = time.time()
c = b - a
print c

آفلاین Ma3X

  • عضو کاربران ایرانی اوبونتو
  • *
  • ارسال: 877
  • جنسیت : پسر
  • It is Matrix
    • ماتریکس. آی آر
استفاده از باقیمانده به صورت مستقیم با ()rand هیچگاه پیشنهاد نمی‌شه. (اگر خواستی می‌تونم دلیلش رو توضیح بدم)

حالا بیا همون برنامه Pythonای که نوشتی رو بدون اینکه توزیع فراوانی‌ اون رو خراب کنیم، کمی تغییر بدیم. خیلی کوچولو! حالا چند ثانیه طول می‌کشه؟
#!/usr/bin/python3
import random
dice = []
def rollDice():
    return int(random.random()*6)
for i in range(6):
    dice.append(0)
for i in range(1, 6000000):
    dice[rollDice()] += 1
for i in range(6):
    print(dice[i], " ")
هر دو مورد رو توضیح می خوام! زمان از ۱۲ به حدود ۴ کاهش پیدا کرد، تغییر تو تابع و به دنبال اون ضرب بود، تابع رندم یه عدد بین ۰ و یک خروجی میده. این تابع تو سرعت دقیقا چه تفاوتی با تابع من داره؟
چرا استفاده از باقیمانده به صورت مستقیم با ()rand  پیشنهاد نمی‌شه؟ بجاش از چی استفاده کنیم؟
پ.ن: بحث ساخت عدد تصادفی تو ریاضی جالب بود، ولی حیف اینجا جاش نیست ...
این کد تو کامپیوتر من توی ۲.۶ ثانیه اجرا شد.

آفلاین امید توانا

  • Hero Member
  • *
  • ارسال: 981
  • جنسیت : پسر
خوب من هم برای مثال یک الگوریتم یکسان رو در پایتون و go میارم (با C++ هم نوشته بودم ولی پیداش نمی‌کنم و حال دوباره نویسی ندارم، ولی زمان اجراش با go زیاد فرقی نداره). الگوریتم تعداد جوابهای مسالهٔ n وزیر رو پیدا می‌کنه.
در PYTHON
#!/usr/bin/python3

import sys
import time

COUNT = 0
BOARD_SIZE = int(sys.argv[1])
ALL = (1<<BOARD_SIZE) - 1

def main():
start = time.clock()
putQueens(0, 0, 0)
elapsed = (time.clock() - start)
print(COUNT, "solutions to ", BOARD_SIZE,"queens in", elapsed, "seconds")

def putQueens(ld, cols, rd):
if cols == ALL:
global COUNT
COUNT += 1
return
pos = ~(ld | cols | rd) & ALL
while pos != 0:
bit = pos & -pos
pos -= bit
putQueens((ld|bit)<<1, cols|bit, (rd|bit)>>1)


if __name__ == "__main__":
main()

و در GO
package main

import (
"fmt"
"os"
"strconv"
"time"
)

var (
all   int
count int
)

func main() {
var size int
size, _ = strconv.Atoi(os.Args[1])
all = 1<<uint(size) - 1

now := time.Now()
try(0, 0, 0)
then := time.Now()

fmt.Printf("%d solutions to %d-queens in %f seconds", count, size, then.Sub(now).Seconds())
}

func try(ld int, cols int, rd int) {
if cols == all {
count++
return
}

pos := ^(ld | cols | rd) & all
for pos != 0 {
bit := pos & -pos
pos -= bit
try((ld|bit)<<1, cols|bit, (rd|bit)>>1)
}
}
و این هم زمان‌های اجرا برای هر دو
در python
92 solutions to  8 queens in 0.0033359999999999987 seconds
352 solutions to  9 queens in 0.013877000000000007 seconds
724 solutions to  10 queens in 0.064723 seconds
2680 solutions to  11 queens in 0.292063 seconds
14200 solutions to  12 queens in 1.542927 seconds
73712 solutions to  13 queens in 7.767173 seconds
365596 solutions to  14 queens in 43.817662000000006 seconds
2279184 solutions to  15 queens in 272.59477599999997 seconds

در go
92 solutions to 8-queens in 0.000087 seconds
352 solutions to 9-queens in 0.000325 seconds
724 solutions to 10-queens in 0.001371 seconds
2680 solutions to 11-queens in 0.003151 seconds
14200 solutions to 12-queens in 0.012581 seconds
73712 solutions to 13-queens in 0.064506 seconds
365596 solutions to 14-queens in 0.358315 seconds
2279184 solutions to 15-queens in 2.234746 seconds
14772512 solutions to 16-queens in 14.877159 seconds

آفلاین ngc0der

  • Full Member
  • *
  • ارسال: 106
قبلا هم مطرح کردم که پایتون در کارهای محاسباتی کنده مگر اینکه از ماژولهای C برای این کارها استفاده بشه. از طرفی نباید یک زبان رو با چند خط کد کلا زیر سوال ببریم و بگیم بدرد نمی خوره.جناب nixoeen بهینه سازی اولیه رو توضیح دادن من کمی ادامه اش میدم.برای بالا بردن سرعت کدهای پایتون راههای زیادی وجود داره که فعلا فقط یکی از اونها رو مطرح می کنم یعنی استفاده از cython که کاربرد اون تولید ماژولهای پایتون با استفاده از زبانی مشابه پایتون هست که به کد C تبدیل و کامپایل میشه.اعدادی که برای زمان ارایه میشه بر حسب ثانیه هستن.
کد اصلی روی لپتاپ من در 8.48531913757 ثانیه اجرا میشه
کد بعد از تغییر nixoeen در 3.06105113029 ثانیه اجرا میشه
حالا یک فایل به اسم hello.pyx برای تولید ماژول به صورت زیر می نویسم:
import random

dice = []
cdef int rollDice():
    return int(random.random()*6)

cdef void _compute():
    cdef int i
    for i in range(7):
        dice.append(0)
    for i in range(1, 6000000):
        dice[rollDice()] += 1
    for i in range(1, 7):
        print(dice[i], " ")

def compute():
    _compute()

همونطور که مشاهده می کنین زبان تولید ماژول ترکیبی از پایتون و سی به نظر می رسه.این ماژول رو کامپایل می کنم و در برنامه ای به شکل زیر استفاده می کنم:
import hello
import time

t = time.time()
hello.compute()
print "time : %s" % str(time.time() - t)

حالا برنامه 0.907082080841 طول می کشه تا اجرا بشه.خب تا اینجا سرعت تقریبا ۱۰ برابر شده.خوبه ولی نه به اندازه کافی!آخرین تغییرات رو هم اعمال می کنم:
import random

cdef extern from "stdlib.h":
    int c_rand "rand"()

cdef int *dice = [0, 0, 0, 0, 0, 0, 0]

cdef int rollDice():
    return c_rand() % 6 + 1

cdef void _compute():
    cdef int i
    for i in range(1, 6000000):
        dice[rollDice()] += 1
    for i in range(1, 7):
        print(dice[i], " ")

def compute():
    _compute()

برنامه رو اجر می کنم که در 0.0859930515289 ثانیه اجرا میشه.خب سرعت تا اینجا نسبت به برنامه اول ۱۰۰ برابر شده.با این مقدار تغییر رسیدن به سرعت ۱۰۰ برابر معقول به نظر می رسه.
به نظر من بهترین حالت استفاده از ابزارهای مناسب به صورت ترکیبی برای رسیدن به نتیجه دلخواه هست وگرنه تعصب راه به جایی نخواهد برد.من خودم بیشتر از هر زبانی با ++c کد زدم ولی این دلیل نمیشه که زبانهای دیگه رو نادیده بگیرم.واقعیت اینه که ++c در پروژه های خیلی بزرگ دردسر ساز میشه به دلیل اینکه نگهداری و تغییر کد هزینه ی زیادی ایجاد می کنه و البته چنین پروژه ای اگه با pure پایتون هم نوشته بشه احتمالا از نظر پرفرمنس وضع دراماتیکی پیدا می کنه! احتمالا راه حل بهتر استفاده ترکیبی از هر دو زبان هست. به نظر من همین قضایا باعث شد گوگل زبان Go رو توسعه بده که به قول خودش تقریبا سرعت ++c/c رو داره و سادگی پایتون رو.البته این زبان فعلا بیشتر به درد نوشتن برنامه های سرور می خوره.
چند وقت پیش یه جایی خوندم "اگر تنها ابزار شما چکش باشد آنگاه با همه چیز مثل میخ رفتار خواهید کرد".هر چیزی در جای خودش باید استفاده بشه وگرنه منابع زیادی تلف میشه.

آفلاین nixoeen

  • ناظر انجمن
  • *
  • ارسال: 4872
  • جنسیت : پسر
  • masoft قدیم
چرا استفاده از باقیمانده به صورت مستقیم با ()rand  پیشنهاد نمی‌شه؟ بجاش از چی استفاده کنیم؟
یک مثال ساده می‌زنم، البته این تنها دلیلش نیست. فرض می‌کنیم که ()rand به ما یک عدد بین ۰ تا ۸ بده. حالا ما ۱۰۰۰۰ تا عدد ایجاد می‌کنیم و بر اساس باقیمانده اون‌ها بر ۶ ببینیم کدوم شماره تاس احتمالا بیشتر تکرار می‌شه. در حالت عادی نباید بتونید حدس بزنید که کدوم عدد بیشتر تکرار می‌شه، ولی اینجا به سادگی می‌شه فهمید که اون عدد ۰ و ۱ و ۲ هستند. دلیلش اینه که دو عدد ۷ و ۱ هر دو بر ۶ باقیمانده ۱ خواهند داشت، ولی برای عدد ۵ تنها عدد ۵ بر ۶ باقیمانده ۵ خواهد داشت.

یکی از روش‌های ساده به جای استفاده از باقیمانده، اینه که ()rand رو بر RAND_MAX تقسیم کنیم تا عددی بین ۰ و ۱ بهمون بده و اون رو در یک عدد دیگه ضرب کنیم و سپس تبدیل به Integer بکنیمش. البته باز بهترین راه نیست، ولی ساده‌ترین راه هستش. در این مورد، کتاب‌هایی مثل The Art of Computer Programming روش‌های مختلف رو خیلی خوب (و البته به زبان ریاضی) توضیح دادند.

()random.random در پایتون تابع پایه هست و کمترین تعداد اجرای تابع‌ها رو داره، در نتیجه سریع‌تر هستش. تابع‌هایی مثل randrange سعی می‌کنند از لحاظ توزیع فراوانی بهترین خروجی رو داشته باشند که این باعث می‌شه اون تابع به راحتی سنگین بشه، ولی در عوض، خروجی بسیار خوبی خواهی داشت، بدون اینکه اطلاعات پایه‌ای زیادی داشته باشی (مثل دو برنامه‌ای که نوشته بودی و برنامه پایتون خروجی بهتری داشت). ولی بدون داشتن اون اطلاعات پایه‌ای، در زبان‌هایی مثل ++C ممکنه برنامه‌ای بنویسی که توی یک شرکت بزرگ، به راحتی باعث آبروریزی می‌شه، مثل اشتباهی که شرکت Microsoft برای ایجاد خروجی تصادفی کرده بود: لینک