رفتن به مطلب
جامعه‌ی برنامه‌نویسان مُدرن ایران
  • 1
قاسم رمضانی منش

بهینه سازی سرعت اجرای برنامه های زبان ++C

سوال

ارسال شده در (ویرایش شده)

با سلام !

دو قطعه برنامه ی زیر یکی آرایه ۱۰۰۰۰۰ تایی در حافظه Stack ساخته و به صورت Random مقداردهی شده و Sort میشود. کد اول به زبان ++C و با استاندارد 11 نوشته شده است که حدود ۷ دقیقه و کد دوم به زبان C نوشته شده است که حدود 1 دقیقه زمان میبرد ! 

CPU Intel i7 M 620 (4) @ 2.667GHz

آیا راهی برای بهینه سازی سرعت اجرای برنامه ی نوشته شده به زبان ++C هست ؟

کد نوشته به زبان ++C :

#include <iostream>
#include <functional>
#include <utility>
#include <array>
#include <random>
#include <chrono>
const unsigned int MAX_LENGTH = 100000;

bool Compare(unsigned int FirstVariable,unsigned int SecondVariable){
  if(FirstVariable < SecondVariable)
    return true;
  return false;
}

void SortArray(std::array<unsigned int,MAX_LENGTH> &MyArray,std::function<bool(unsigned int,unsigned int)> function){
  for(unsigned int index=0;index < MAX_LENGTH;++index)
      for(unsigned int AnotherIndex=0;AnotherIndex<MAX_LENGTH;++AnotherIndex)
          if(function(MyArray[index],MyArray[AnotherIndex]))
            std::swap(MyArray[index],MyArray[AnotherIndex]);
}

void PrintArrayElements(const std::array<unsigned int,MAX_LENGTH> &MyArray){
  for(const auto &item : MyArray)
    std::cout << item << std::endl;
}

void RandomizeArray(std::array<unsigned int,MAX_LENGTH> &MyArray){
  std::mt19937_64 Random(static_cast<int>(std::chrono::high_resolution_clock::now().time_since_epoch().count()));
  std::uniform_int_distribution<> RandomGenerator(0,1000);
  for(unsigned int index=0;index<MAX_LENGTH;++index)
    MyArray[index] = static_cast<unsigned int>(RandomGenerator(Random));
}

int main(){
  std::array<unsigned int,MAX_LENGTH> MyOrginalArray;
  RandomizeArray(MyOrginalArray);
  SortArray(MyOrginalArray,Compare);
  PrintArrayElements(MyOrginalArray);
  return 0x0000;
}

کد نوشته شده به زبان C :
 

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#define MAX_LENGTH 100000
bool Compare(unsigned int FirstVariable,unsigned int SecondVariable){
  if(FirstVariable < SecondVariable)
    return true;
  return false;
}
void SortArray(unsigned int *MyArray,bool (*compare)(unsigned int,unsigned int)){
  unsigned int tmp=0;
  for(unsigned int index=0;index < MAX_LENGTH;++index){
      for(unsigned int AnotherIndex=0;AnotherIndex<MAX_LENGTH;++AnotherIndex){
          if(compare(MyArray[index],MyArray[AnotherIndex])){
            tmp = MyArray[index];
            MyArray[index] = MyArray[AnotherIndex];
            MyArray[AnotherIndex] = tmp;
          }
        }
    }
}

void RandomizeArray(unsigned int *MyArray){
  srand(time(NULL));
  for(unsigned int index=0;index < MAX_LENGTH ;++index)
    MyArray[index] = rand() % 1000;
}

void PrintArrayElements(unsigned int *MyArray){
  for(unsigned int index=0;index<MAX_LENGTH;++index)
    fprintf(stdout,"%d\n",MyArray[index]);
}

int main(){
  unsigned int Array[MAX_LENGTH];
  RandomizeArray(Array);
  SortArray(Array,Compare);
  PrintArrayElements(Array);
  return 0x0000;
}

 

ویرایش شده در توسط قاسم رمضانی منش
  • پسندیدن 1

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر

15 پاسخ به این سوال تا کنون داده شده است

پست های پیشنهاد شده

  • 1
در 4 ساعت قبل، قاسم رمضانی منش گفته است :

با سلام !

دو قطعه برنامه ی زیر یکی آرایه ۱۰۰۰۰۰ تایی در حافظه Stack ساخته و به صورت Random مقداردهی شده و Sort میشود.

کد اول به زبان ++C و با استاندارد 11 نوشته شده است که حدود ۷ دقیقه و کد دوم به زبان C نوشته شده است که حدود 1 دقیقه زمان میبرد ! 

CPU Intel i7 M 620 (4) @ 2.667GHz

آیا راهی برای بهینه سازی سرعت اجرای برنامه ی نوشته شده به زبان ++C هست ؟

 

کد نوشته به زبان ++C :


#include <iostream>
#include <functional>
#include <utility>
#include <array>
#include <random>
#include <chrono>
const unsigned int MAX_LENGTH = 100000;

bool Compare(unsigned int FirstVariable,unsigned int SecondVariable){
  if(FirstVariable < SecondVariable)
    return true;
  return false;
}

void SortArray(std::array<unsigned int,MAX_LENGTH> &MyArray,std::function<bool(unsigned int,unsigned int)> function){
  for(unsigned int index=0;index < MAX_LENGTH;++index)
      for(unsigned int AnotherIndex=0;AnotherIndex<MAX_LENGTH;++AnotherIndex)
          if(function(MyArray[index],MyArray[AnotherIndex]))
            std::swap(MyArray[index],MyArray[AnotherIndex]);
}

void PrintArrayElements(const std::array<unsigned int,MAX_LENGTH> &MyArray){
  for(const auto &item : MyArray)
    std::cout << item << std::endl;
}

void RandomizeArray(std::array<unsigned int,MAX_LENGTH> &MyArray){
  std::mt19937_64 Random(static_cast<int>(std::chrono::high_resolution_clock::now().time_since_epoch().count()));
  std::uniform_int_distribution<> RandomGenerator(0,1000);
  for(unsigned int index=0;index<MAX_LENGTH;++index)
    MyArray[index] = static_cast<unsigned int>(RandomGenerator(Random));
}

int main(){
  std::array<unsigned int,MAX_LENGTH> MyOrginalArray;
  RandomizeArray(MyOrginalArray);
  SortArray(MyOrginalArray,Compare);
  PrintArrayElements(MyOrginalArray);
  return 0x0000;
}

کد نوشته شده به زبان C :
 


#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#define MAX_LENGTH 100000
bool Compare(unsigned int FirstVariable,unsigned int SecondVariable){
  if(FirstVariable < SecondVariable)
    return true;
  return false;
}
void SortArray(unsigned int *MyArray,bool (*compare)(unsigned int,unsigned int)){
  unsigned int tmp=0;
  for(unsigned int index=0;index < MAX_LENGTH;++index){
      for(unsigned int AnotherIndex=0;AnotherIndex<MAX_LENGTH;++AnotherIndex){
          if(compare(MyArray[index],MyArray[AnotherIndex])){
            tmp = MyArray[index];
            MyArray[index] = MyArray[AnotherIndex];
            MyArray[AnotherIndex] = tmp;
          }
        }
    }
}

void RandomizeArray(unsigned int *MyArray){
  srand(time(NULL));
  for(unsigned int index=0;index < MAX_LENGTH ;++index)
    MyArray[index] = rand() % 1000;
}

void PrintArrayElements(unsigned int *MyArray){
  for(unsigned int index=0;index<MAX_LENGTH;++index)
    fprintf(stdout,"%d\n",MyArray[index]);
}

int main(){
  unsigned int Array[MAX_LENGTH];
  RandomizeArray(Array);
  SortArray(Array,Compare);
  PrintArrayElements(Array);
  return 0x0000;
}

 

من قبلاً در گروه به این مساله اشاره کرده بودم که همیشه نباید از ویژگی‌های جدید انتظار داشت که در هر جایی نتیجه‌ی خوبی رو ارائه بدن، چون هر ویژگی در جای مناسب خودش کاربرد داره نه در هر جا!

کد شما با پیشنهاداتی که دوستان دادن می‌تونه بهینه بشه حتی سریع‌تر از C! اما درستش اینه که از ویژگی std::function در چنین مواردی استفاده نکنید! به جاش از روش بهتری مانند template استفاده کنید.

تابع SortArray رو به روش زیر باز‌نویسی کنید:

template<typename T>
void SortArray(std::array<unsigned int,MAX_LENGTH> &MyArray,T function){
  for(unsigned int index=0;index < MAX_LENGTH;++index)
      for(unsigned int AnotherIndex=0;AnotherIndex<MAX_LENGTH;++AnotherIndex)
          if(function(MyArray[index],MyArray[AnotherIndex]))
            std::swap(MyArray[index],MyArray[AnotherIndex]);
}

مشخصات پلتفرم:

پردازنده : Intel® Core™ i5-2400 CPU @ 3.10GHz × 4

سیستم‌عامل‌ : لینوکس ابنتو ۱۸.۱۰

مد کامپایل : Debug

قبل از باز‌نویسی کُد تحت Clang نتیجه‌ی زیر رو گرفتم:

photo_2018-11-29_20-08-56.jpg

بعد از باز‌نویسی کُد تحت GCC 8.x نتیجه زیر:

photo_2018-11-29_20-09-42.jpg

در نهایت بهترین نتیحه بدون بهینه سازی کامپایلر و یا تغییر در نحوه‌ی پردازش روی Clang 7.x نتیجه‌ی زیر رو دریافت می‌کنم.

photo_2018-11-29_20-09-37.jpg

اینم مُد Release برای GCC 8.x

photo_2018-11-29_22-43-35.jpg

اینم مُد Release برای Clang 7.x

photo_2018-11-29_22-43-24.jpg

از پیشنهادات دوستان هم برای بهینه سازی بیشتر می‌تونید استفاده کنید. البته پیشنهاد می‌کنم هیچوقت تنظیمات پیشفرض کامپایلر رو تغییر ندین، به جای این کار بهتره کد‌ها باز‌نویسی و بهینه نویسی شوند.

  • پسندیدن 2
  • تشکر شده 1

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 1

سلام بر حاج قاسم

با تست اول به طور طبیعی روی لینوکس و لپتاپ خودم با کامپایلر g++-8 خروجی شد :

315 ثانیه معادل 5.25 دقیقه

حالا تست دوم با تنظیم کردن دو تا فلگ برای بهینه سازی فلگ های -O3 و -ffast-math

نتیجه شد :

26 ثانیه

بدون دست بردن توی کد تونستم با ست کردن فلگ بهینه سازی زمان رو کاهش بدم.

 

  • پسندیدن 2
  • تشکر شده 1

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 1
در 2 ساعت قبل، قاسم رمضانی منش گفته است :

با سلام !

دو قطعه برنامه ی زیر یکی آرایه ۱۰۰۰۰۰ تایی در حافظه Stack ساخته و به صورت Random مقداردهی شده و Sort میشود.

کد اول به زبان ++C و با استاندارد 11 نوشته شده است که حدود ۷ دقیقه و کد دوم به زبان C نوشته شده است که حدود 1 دقیقه زمان میبرد ! 

CPU Intel i7 M 620 (4) @ 2.667GHz

آیا راهی برای بهینه سازی سرعت اجرای برنامه ی نوشته شده به زبان ++C هست ؟

 

کد نوشته به زبان ++C :


#include <iostream>
#include <functional>
#include <utility>
#include <array>
#include <random>
#include <chrono>
const unsigned int MAX_LENGTH = 100000;

bool Compare(unsigned int FirstVariable,unsigned int SecondVariable){
  if(FirstVariable < SecondVariable)
    return true;
  return false;
}

void SortArray(std::array<unsigned int,MAX_LENGTH> &MyArray,std::function<bool(unsigned int,unsigned int)> function){
  for(unsigned int index=0;index < MAX_LENGTH;++index)
      for(unsigned int AnotherIndex=0;AnotherIndex<MAX_LENGTH;++AnotherIndex)
          if(function(MyArray[index],MyArray[AnotherIndex]))
            std::swap(MyArray[index],MyArray[AnotherIndex]);
}

void PrintArrayElements(const std::array<unsigned int,MAX_LENGTH> &MyArray){
  for(const auto &item : MyArray)
    std::cout << item << std::endl;
}

void RandomizeArray(std::array<unsigned int,MAX_LENGTH> &MyArray){
  std::mt19937_64 Random(static_cast<int>(std::chrono::high_resolution_clock::now().time_since_epoch().count()));
  std::uniform_int_distribution<> RandomGenerator(0,1000);
  for(unsigned int index=0;index<MAX_LENGTH;++index)
    MyArray[index] = static_cast<unsigned int>(RandomGenerator(Random));
}

int main(){
  std::array<unsigned int,MAX_LENGTH> MyOrginalArray;
  RandomizeArray(MyOrginalArray);
  SortArray(MyOrginalArray,Compare);
  PrintArrayElements(MyOrginalArray);
  return 0x0000;
}

کد نوشته شده به زبان C :
 


#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#define MAX_LENGTH 100000
bool Compare(unsigned int FirstVariable,unsigned int SecondVariable){
  if(FirstVariable < SecondVariable)
    return true;
  return false;
}
void SortArray(unsigned int *MyArray,bool (*compare)(unsigned int,unsigned int)){
  unsigned int tmp=0;
  for(unsigned int index=0;index < MAX_LENGTH;++index){
      for(unsigned int AnotherIndex=0;AnotherIndex<MAX_LENGTH;++AnotherIndex){
          if(compare(MyArray[index],MyArray[AnotherIndex])){
            tmp = MyArray[index];
            MyArray[index] = MyArray[AnotherIndex];
            MyArray[AnotherIndex] = tmp;
          }
        }
    }
}

void RandomizeArray(unsigned int *MyArray){
  srand(time(NULL));
  for(unsigned int index=0;index < MAX_LENGTH ;++index)
    MyArray[index] = rand() % 1000;
}

void PrintArrayElements(unsigned int *MyArray){
  for(unsigned int index=0;index<MAX_LENGTH;++index)
    fprintf(stdout,"%d\n",MyArray[index]);
}

int main(){
  unsigned int Array[MAX_LENGTH];
  RandomizeArray(Array);
  SortArray(Array,Compare);
  PrintArrayElements(Array);
  return 0x0000;
}

 

معمولا خیلی بهتره که اینطور پردازش های سنگین را به صورت موازی انجام بدید مثلا از تکنیک Divide and Concur استفاده کنید.

ولی با تغییراتی که دادم برای 20000 تا تقریبا 3 ثانیه طول کشید که سورت کنه!

#include <iostream>
#include <functional>
#include <utility>
#include <array>
#include <random>
#include <chrono>
const unsigned int MAX_LENGTH = 20000;

bool Compare(unsigned int* FirstVariable,unsigned int* SecondVariable){
  if(FirstVariable < SecondVariable)
    return true;
  return false;
}
void swapData(unsigned int* ji,unsigned int* ci){
    unsigned int* tmp=0;
    tmp = ci;
    ci = ji;
    ji = tmp;
}

void SortArray(std::array<unsigned int*,MAX_LENGTH> &MyArray,bool (*compare)(unsigned int*,unsigned int*)){
       for(std::array<unsigned int*,MAX_LENGTH>::iterator ci=MyArray.begin(); ci !=MyArray.end(); ++ci){
           for(std::array<unsigned int*,MAX_LENGTH>::iterator ji=ci; ji !=MyArray.end(); ++ji){
              if(compare((*ji),(*ci)))
                 swapData(*ji , *ci);
           }
       }
}



void PrintArrayElements(const std::array<unsigned int*,MAX_LENGTH> &MyArray){
  for(const auto &item : MyArray)
    std::cout << item << std::endl;
}

void RandomizeArray(std::array<unsigned int*,MAX_LENGTH> &MyArray){
  std::mt19937_64 Random(static_cast<int>(std::chrono::high_resolution_clock::now().time_since_epoch().count()));
  std::uniform_int_distribution<> RandomGenerator(0,1000);
  for(unsigned int index=0;index<MAX_LENGTH;++index)
    MyArray[index] = (unsigned int*)RandomGenerator(Random);
}

int main(){
  std::array<unsigned int*,MAX_LENGTH> MyOrginalArray;
  RandomizeArray(MyOrginalArray);
  SortArray(MyOrginalArray,Compare);
  //PrintArrayElements(MyOrginalArray);
  return 0x0000;
}

البته وقتی از STL استفاده میکنید کمی از سرعت پردازش را دارید فدای کیفیت کد نویسی میکنید واین خیلی وقتها بیشتر اهمیت داره تا سرعت پردازش همانطور که گفتم برای رفع مشکلات مربوط به سرعت پردازش از تکنیکهای موازی استفاده می شود.

  • پسندیدن 2

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 1

استفاده از توزیع‌های آماری برای تولید اعداد تصادفی سرعت رو پایین میاره. چون مشخهٔ آماری توزیع (مثلاً توی مورد شما توزیع یکسان) باید در هنگام تولید اعداد رعایت بشه. به همین خاطر موقع تولید عدد ممکنه سه یا چهار بار عدد تصادفی تولید بشه. این مسأله موقع استفاده از توزیع‌های آماری پیچیده‌تر مثل توزیع نرمال شدیدتر هم میشه. تولید عدد تصادفی با توزیع نرمال در سی‌پلاس‌پلاس خیلی کنده. در مقابل اگر مشخصهٔ آماری براتون مهم نیست می‌تونید از توابع سادهٔ rand استفاده کنید که از سخت‌افزار هم برای تولید عدد تصادفی کمک می‌گیرند:

cat /dev/urandom | hexdump
 

سرعت تولید عدد تصادفی به این روش خیلی بالاست اما آشفتگی لازم برای رمزنگاری رو نداره. اگه کاربرد خیلی جدی هست باید از randomبه‌جاش استفاده کنید که کندتره. توابع استاندارد هم  از همین‌ها استفاده می‌کنند.

 

 

  • تشکر شده 3

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 0
ارسال شده در (ویرایش شده)
در 19 دقیقه قبل، بهنام صباغی گفته است :

حالا تست دوم با تنظیم کردن دو تا فلگ برای بهینه سازی فلگ های -O3 و -ffast-math

مرسی متشکرم.

بله سرعت رو به شدت بالابرد !

اما !

این فلگ هایی که گفتید فقط فلگ اول O3- برای بهینه سازی هست که باعث افزایش سرعت میشه.

و فلگ دوم ffast-math- به کامپایلر اجازه میده که یک سری از قوانین IEEE و ISO و نقض کنه  :

GCC Command Options

و گفته شده که در صورت استفاده از فلگ ffast-math- از هیچ کدام سطح های بهینه سازی O- استفاده نکنید که باعث خروجی اشتباه میشه !

ویرایش شده در توسط قاسم رمضانی منش
مشخص کردن دقیق فلگ افزایش دهنده سرعت.
  • پسندیدن 1

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 0
در 16 دقیقه قبل، بهنام صباغی گفته است :

سلام بر حاج قاسم

با تست اول به طور طبیعی روی لینوکس و لپتاپ خودم با کامپایلر g++-8 خروجی شد :

315 ثانیه معادل 5.25 دقیقه

حالا تست دوم با تنظیم کردن دو تا فلگ برای بهینه سازی فلگ های -O3 و -ffast-math

نتیجه شد :

26 ثانیه

بدون دست بردن توی کد تونستم با ست کردن فلگ بهینه سازی زمان رو کاهش بدم.

 

آقا نکته ی جالبی گفتی حداقل برای من که جالب بود چون من معمولا این فلگ ها را تغییر نمیدم

تشکر

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 0
در 3 دقیقه قبل، قاسم رمضانی منش گفته است :

مرسی متشکرم.

بله سرعت رو به شدت بالابرد !

اما !

این فلگ هایی که گفتید فقط فلگ اول O3- برای بهینه سازی هست. و فلگ دوم ffast-math- به کامپایلر اجازه میده که یک سری از قوانین IEEE و ISO و نقض کنه که باعث افزایش سرعت میشه :

GCC Command Options

و گفته شده که در صورت استفاده از فلگ ffast-math- از هیچ کدام سطح های بهینه سازی O- استفاده نکنید که باعث خروجی اشتباه میشه !

به همین علت هم معمولا توصیه نمیشه که فلگ های کامپایلر را تغییر داد چون با اینکه روی سیستم خودتون درست جواب میده ولی می تونه تو سیستم های دیگه معماری های دیگه دچار باگ بشه!

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 0
در 3 دقیقه قبل، فرهاد شیری گفته است :

آقا نکته ی جالبی گفتی حداقل برای من که جالب بود چون من معمولا این فلگ ها را تغییر نمیدم

تشکر

اره منم تغییر نمیدادم ولی چند روزی هست درگیر بهینه سازی هستیم جالبه که فعال کردن این فلگ ها علاوه بر بالا بردن سرعت باعث میشه کد اسمبلی یکم پیچیده تر بشه و برای مهندسی معکوس سخت تر بشه کار اینطور که شنیدم ولی تست نکردم هنوز .

 

  • پسندیدن 1
  • تشکر شده 1

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 0
در 7 دقیقه قبل، فرهاد شیری گفته است :
در 2 ساعت قبل، قاسم رمضانی منش گفته است :

 

معمولا خیلی بهتره که اینطور پردازش های سنگین را به صورت موازی انجام بدید مثلا از تکنیک Divide and Concur استفاده کنید.

ولی با تغییراتی که دادم برای 20000 تا تقریبا 3 ثانیه طول کشید که سورت کنه!

مرسی ممنون حتما درباره این تکنیک جستجو میکنم.

با تغییراتی که دادید سرعت را از  ۷ دقیقه به ۱ دقیقه کاهش دادید !. (شما با مقدار ۲۰۰۰۰ هزار اجرا کرده بودید. مقدار پیش فرض ۱۰۰۰۰۰ بود.)

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 0
در 1 دقیقه قبل، قاسم رمضانی منش گفته است :

مرسی ممنون حتما درباره این تکنیک جستجو میکنم.

با تغییراتی که دادید سرعت را از  ۷ دقیقه به ۱ دقیقه کاهش دادید !. (شما با مقدار ۲۰۰۰۰ هزار اجرا کرده بودید. مقدار پیش فرض ۱۰۰۰۰۰ بود.)

بله دیگه وقتی حجم آرایه را بالاتر می برید طبیعی هست دیگه پردازش چند برابر زمان میبره البته می تونید از الگوریتم های باینری استفاده کنید تا همین یک دقیقه هم یه 30تا 40 ثانیه تقلیل پیدا کنه ! والبته الگوریتم های مرتب سازی های دیگه را هم تست کنید ولی من خودم برای این طور کار از وکتور و الگوریتم ها استفاده میکنم برای همین سرعت خیلی بهتر میشه!

  • پسندیدن 1

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 0
در 6 دقیقه قبل، فرهاد شیری گفته است :

الگوریتم های مرتب سازی های دیگه را هم تست کنید

بله ! صدالبته که عملکرد انواع الگوریتم ها و روششون میتونه توی سرعت تاثیر داشته باشه.

مثل اینکه درست منظور خودم را نگفتم:) هردو کدی که ارسال کردم به یک روش نوشته شده اند ولی یکی به زبان سی پلاس پلاس و با استفاده از کتابخانه های استاندارد و یکی با استفاده از زبان سی و کتابخونه های استاندارد خودش. 

البته این مورد بدیهی هست که سرعت کمی از سی به سی پلاس پلاس کاهش پیدا کنه. که بنده دنبال راهی بودم برای رفع این مشکل که آقا بهنام با معرفی فلگ بهینه سازی O- تا حدود بسیار زیادی این مشکل رو برطرف کردن.

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 0
در 9 دقیقه قبل، قاسم رمضانی منش گفته است :

بله ! صدالبته که عملکرد انواع الگوریتم ها و روششون میتونه توی سرعت تاثیر داشته باشه.

مثل اینکه درست منظور خودم را نگفتم:) هردو کدی که ارسال کردم به یک روش نوشته شده اند ولی یکی به زبان سی پلاس پلاس و با استفاده از کتابخانه های استاندارد و یکی با استفاده از زبان سی و کتابخونه های استاندارد خودش. 

البته این مورد بدیهی هست که سرعت کمی از سی به سی پلاس پلاس کاهش پیدا کنه. که بنده دنبال راهی بودم برای رفع این مشکل که آقا بهنام با معرفی فلگ بهینه سازی O- تا حدود بسیار زیادی این مشکل رو برطرف کردن.

اره دیگه اگر صرف زمان مهم بود کتابخونه معرفی میکردم که با پارالل کردن فور بدون تغییر زیاد توی کد بتونی سرعتت رو خیلی زیاد کنی

مثلا استفاده از openmp میتونه خیلی کمک کنه

  • پسندیدن 1

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 0
در 22 دقیقه قبل، بهنام صباغی گفته است :

اره دیگه اگر صرف زمان مهم بود کتابخونه معرفی میکردم که با پارالل کردن فور بدون تغییر زیاد توی کد بتونی سرعتت رو خیلی زیاد کنی

مثلا استفاده از openmp میتونه خیلی کمک کنه

من همین الان کدت رو بدون تغییر با openmp تست کردم زمان شگفت انگیز شد :

real 0m6.534s user 0m49.599s sys 0m0.255s

یعنی حدودا 6 ثانیه و نیم

راضی هستی یا بهترش کنم ؟ 

^_^

این هم کد که البته تغییری نکرده فقط سه خط ماکرو برای openmp اضافه شده :


#include <array>
#include <chrono>
#include <functional>
#include <iostream>
#include <random>
#include <utility>
const unsigned int MAX_LENGTH = 100000;

bool Compare(unsigned int FirstVariable, unsigned int SecondVariable)
{
	if (FirstVariable < SecondVariable) return true;
	return false;
}

void SortArray(std::array<unsigned int, MAX_LENGTH> &MyArray,
		   std::function<bool(unsigned int, unsigned int)> function)
{
#pragma omp parallel for
	for (unsigned int index = 0; index < MAX_LENGTH; ++index)
	{
#pragma omp parallel for

		for (unsigned int AnotherIndex = 0; AnotherIndex < MAX_LENGTH;
		 ++AnotherIndex)
		{
			if (function(MyArray[index], MyArray[AnotherIndex]))
			{
				std::swap(MyArray[index], MyArray[AnotherIndex]);
			}
		}
	}
}

void PrintArrayElements(const std::array<unsigned int, MAX_LENGTH> &MyArray)
{
	for (const auto &item : MyArray)
	std::cout << item << std::endl;
}

void RandomizeArray(std::array<unsigned int, MAX_LENGTH> &MyArray)
{
	std::mt19937_64 Random(static_cast<int>(
	std::chrono::high_resolution_clock::now().time_since_epoch().count()));
	std::uniform_int_distribution<> RandomGenerator(0, 1000);
#pragma omp parallel for
	for (unsigned int index = 0; index < MAX_LENGTH; ++index)
	MyArray[index] = static_cast<unsigned int>(RandomGenerator(Random));
}

int main()
{
	std::array<unsigned int, MAX_LENGTH> MyOrginalArray;
	RandomizeArray(MyOrginalArray);
	SortArray(MyOrginalArray, Compare);
	PrintArrayElements(MyOrginalArray);
	return 0x0000;
}

 

  • پسندیدن 1

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 0
در 21 دقیقه قبل، بهنام صباغی گفته است :

یعنی حدودا 6 ثانیه و نیم

راضی هستی یا بهترش کنم ؟

درمورد کتابخونه ای که گفتی دارم الان یه چیز هایی میخونم :X واقعا عالیه ! همین ابزار در کنار قدرت بهینه سازی که خودمون میتونیم توی کد اعمال کنیم مثل مواردی که آقای شیری و اسدزاده گفتن سرعت فوق العاده ای رومیتونیم داشته باشیم  :classic_biggrin:.

مرسی آقا بهنام راضی راضی ام متشکر :classic_ninja:

 

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 0
در ۱ ساعت قبل، بهنام صباغی گفته است :

اره دیگه اگر صرف زمان مهم بود کتابخونه معرفی میکردم که با پارالل کردن فور بدون تغییر زیاد توی کد بتونی سرعتت رو خیلی زیاد کنی

مثلا استفاده از openmp میتونه خیلی کمک کنه

آقا خوشم میاد تو کانال هم برای هر مسئله ای یک کتابخانه تو آستین داری یعنی کتابخانه ملی هم انقد کتابخانه نداره که شما داری😁

  • هاها! 2

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر

برای ارسال دیدگاه یک حساب کاربری ایجاد کنید یا وارد حساب خود شوید

برای اینکه بتوانید دیدگاهی ارسال کنید نیاز دارید که کاربر سایت شوید

ایجاد یک حساب کاربری

برای حساب کاربری جدید در سایت ما ثبت نام کنید. عضویت خیلی ساده است !

ثبت نام یک حساب کاربری جدید

ورود به حساب کاربری

دارای حساب کاربری هستید؟ از اینجا وارد شوید

ورود به حساب کاربری

  • کاربران آنلاین در این صفحه   0 کاربر

    هیچ کاربر عضوی،در حال مشاهده این صفحه نیست.

  • مطالب مشابه

    • توسط کامبیز اسدزاده
      در این مقاله من قصد دارم در رابطه با تفاوت‌های اختصاص دادن حافظه در اِستک و هیپ توضیحاتی دهم که بسیاری از علاقه‌مندان راجب آن‌ها سوال کرده اند.
      با توجه به اینکه، از اوایل سیستم‌های کامپیوتری این تمایز در این وجود داشته است که برنامه های اصلی در حافظه فقط خواندنی مانند ROM ٬ PROM و یا EEPROM نگه داری می‌شوند. به عنوان دیگر از زمانی که سیستم ها پیچیده تر شدند برنامه ها از حافظه های دیگری مانند RAM به جای اجرا در حافظه ROM استفاده کردند. این ایده به خاطر این بود که تعدادی از قسمت های حافظه مربوط به برنامه نباید تغییر یابند و در این حالت باید حفظ شوند. در این میان دو بخش .text و .rodata بخشی‌هایی از برنامه هستند که می‌تواند به بخش های دیگر برای وظایف خاص تقسیم شوند که در ادامه به آن‌ها اشاره شده است.
      بخش کد، به عنوان یک بخش متنی (.text) و یا به طور ساده به عنوان متن شناخته می‌شود. جایی است که بخشی از یک فایل شیء یا بخش مربوطه از فضای آدرس مجازی برنامه که حاوی دستورالعمل های اجرایی است و به طور کلی فقط خواندنی بوده و اندازه ثابتی دارد می‌باشد. بخش .bss که به عنوانی بخشی ویژه (محل نگه داری اطلاعات تخصیص داده نشده (مقدار دهی نشده)) محلی که متغیر‌های سراسری و ثابت با مقدار صفر شروع می‌شوند. بخش داده (.data) حاوی هر گونه متغیر سراسری و یا استاتیک که دارای یک مقدار از پیش تعریف شده هستند و می‌توانند اصلاح شوند. تصویر زیر طرح معمولی از یک حافظه برنامه ساده کامپیوتری را با متن٬ داده های مختلف٬ و بخش‌های استک و هیپ و bss را نشان می‌دهد.

      برای مثال در کد C به صورت زیر خواهد بود:
      int val = 3; char string[] = "Hello World"; مقادیر برای این نوع متغیر‌ها در ابتدا در حافظه فقط خواندنی ذخیره می‌شوند. (معمولا در داخل .text) و در زمان اجرای برنامه که به صورت روتین خواهد بود در بخش .data کپی می‌شوند.
      بخش BSS یا همان .BSS
      در برنامه نویسی کامپیوتری، نام .bss یا bss توسط بسیاری از کامپایلرها و لینکرها برای بخشی از دیتا سِگمنت (Data Segment) استفاده می‌شود که حاوی متغیر های استاتیک اختصاصی که تنها از بیت هایی با ارزش صفر شروع شده است می‌باشد. این بخش به عنوان BSS Section و یا BSS Segment شناخته می‌شود.
      به طور معمول فقط طول بخش bss نه data در فایل آبجکت ذخیره می‌شود. برای نمونه، یک متغیر به عنوان استاتیک تعریف شده است static int i; این در بخش BSS خواهد بود.
      حافظه هیپ (Heap)
       ناحیه هیپ (Heap) به طور رایج در ابتدای بخش‌های .bss و .data قرار گرفته است و به اندازه‌های آدرس بزرگتر قابل رشد است. ناحیه هیپ توسط توابع malloc, calloc, realloc و free مدیریت می‌شود که ممکن است توسط سیستم‌های brk و sbrk جهت تنظیم اندازه مورد استفاده قرار گیرد. ناحیه هیپ توسط تمامی نخ‌ها٬ کتابخانه‌های مشترک و ماژول‌های بارگذاری شده در یک فرآیند به اشتراک گذاشته می‌شود.
      به طور کلی حافطه Heap بخشی از حافظه کامپیوتر شما است که به صورت خودکار برای شما مدیریت نمی‌شود، و به صورت محکم و مطمئن توسط پردازنده مرکزی مدیریت نمی‌شود. آن بیشتر به عنوان یک ناحیه شناور بسیار بزرگی از حافظه است. برای اختصاص دادن حافظه در ناحیه هیپ شما باید از توابع malloc(), calloc() که توابعی از C هستند استفاده کنید. یکبار که شما حافظه ای را در ناحیه هیپ اختصاص دهید، جهت آزاد سازی آن باید خود مسئول باشید و با استفاده از تابع free() این کار را به صورت دستی جهت آزاد سازی حافظه اختصاص یافته شده انجام دهید. اگر شما در این کار موفق نباشید، برنامه شما در وضعیت نَشت حافظه (Memory Leak) قرار خواهد گرفت. این بدین معنی است که حافظه اختصاص یافته شده در هیپ هنوز خارح از دسترس قرار گرفته و مورد استفاده قرار نخواهد گرفت. این وضعیت همانند گرفتگی رَگ در بدن انسان است و حافظه نشت شده جهت عملیات در دسترس نخواهد بود. خوشبختانه ابزار‌هایی برای کمک کردن به شما در این زمینه موجود هستند که یکی از آن‌ها Valgrind نام دارد و شما می‌توانید در زمان اشکال زدائی از آن جهت تشخیص نواحی نشت دهنده حافظه استفاده کنید.
      بر خلاف حافظه اِستک (Stack) حافظه هیپ محدودیتی در اندازه متغیر‌ها ندارد (جدا از محدودیت آشکار فیزیکی در کامپیوتر شما). حافظه هیپ در خواندن کمی کُند تر از نوشتن نسبت به حافظه اِستک است، زیرا جهت دسترسی به آن‌ها در حافظه هیپ باید از اشاره گر استفاده شود. بر خلاف حافظه اِستک، متغیر‌هایی که در حافظه هیپ ساخته می‌شوند توسط هر تابعی در هر بخشی از برنامه شما در دسترس بوده و اساسا متغیر‌های تعریف شده در هیپ در دامنه سراسری قرار دارند.
       
      حافظه اِستک (Stack)
      ناحیه اِستک (Stack) شامل برنامه اِستک٬ با ساختار LIFO کوتاه‌ شده عبارت Last In First Out (آخرین ورودی از همه زودتر خارج می‌شود) به طور رایج در بالاترین بخش از حافظه قرار می‌گیرد. یک (اشاره گر پشته) در بالاترین قسمت اِستک قرار می‌گیرد. زمانی که تابعی فراخوانی می‌شود این تابع به همراه تمامی متغیرهای محلی خودش در داخل حافظه اِستک قرار می‌گیرد و با فراخوانی یک تابع جدید تابع جاری بر روی تابع قبلی قرار می‌گیرد و کار به همین صورت درباره دیگر توابع ادامه پیدا می‌کند.
      مزیت استفاده از حافظه اِستک در ذخیره متغیرها است، چرا که حافظه به صورت خودکار برای شما مدیریت می‌شود. شما نیازی برای اختصاص دادن حافظه به صورت دستی ندارید، یا نیازی به آزاد سازی حافظه ندارید. به طور کلی دلیل آن نیز این است که حافظه اِستک به اندازه کافی توسط پردازنده مرکزی بهینه و سازماندهی می‌شود. بنابراین خواندن و نوشتن در حافظه اِستک بسیار سریع است.
      کلید درک حافظه اِستک در این است که زمانی که تابع خارج می‌شود، تمامی متغیر‌های موجود در آن همراه با آن خارج و به پایان زندگی خود میرسند. بنابراین متغیر‌های موجود در حافظه اِستک به طور طبیعی به صورت محلی هستند. این مرتبط با مفهوم دامنه متغیر‌ها است که قبلا از آن یاد شده است، یا همان متغیر‌های محلی در مقابل متغیر‌های سراسری. 
      یک اشکال رایج در برنامه نویسی C تلاش برای دسترسی به یک متغیر که در حافظه اِستک برای یک تابع درونی ساخته شده است می‌باشد. یعنی از یک مکان در برنامه شما به خارج از تابع (یعنی زمانی که آن تابع خارج شده باشد) رجوع می‌کند.
      یکی دیگر از ویژگی‌های حافظه اِستک که بهتر است به یاد داشته باشید این است که٬ محدودیت اندازه (نسبت به نوع سیستم عامل متفاوت) است. این مورد در حافظه هیپ صدق نمی‌کند.
      خلاصه ای از حافظه اِستک (Stack)
      حافظه اِستک متناسب با ورود و خروج توابع و متغیر‌های درونی آن‌ها افزایش و کاهش می‌یابد نیازی برای مدیریت دستی حافظه برای شما وجود ندارد٬ حافظه به طور خودکار برای متغیر‌ها اختصاص و در زمان نیاز به صورت خودکر آزاد می‌شود در اِستک اندازه محدود است متغیر‌های اِستک تنها در زمان اجرای تابع ساخته می‌شوند مزایا و معایب حافظه اِستک و هیپ
        حافظه اِستک (Stack)
      دسترسی بسیار سریع به متغیر‌ها نیازی برای باز پس گیری حافظه اختصاص یافته شده ندارید فضا در زمان مورد نیاز به اندازه کافی توسط پردازنده مرکزی مدیریت می‌شود، حافظه ای نشت نخواهد کرد متغیر‌ها فقط محلی هستند محدودیت در حافظه اِستک بسته به نوع سیستم عامل متفاوت است متغیر‌ها نمی‌توانند تغییر اندازه دهند حافظه هیپ (Heap) متغیر‌ها به صورت سراسری قابل دسترس هستند محدودیتی در اندازه حافظه وجود ندارد تضمینی برای حافظه مصرفی وجود ندارد، ممکن است حافظه در زمان‌های خاص از برنامه نشت کرده و حافظه اختصاص یافته شده برای استفاده در عملیات دیگر آزاد نخواهد شد شما باید حافظه را مدیریت کنید٬ شما باید مسئولیت آزاد سازی حافظه های اختصاص یافته شده به متغیر‌ها را بر عهده بگیرید اندازه متغیر‌ها می‌تواند توسط تابع realloc() تغییر یابد در اینجا یک برنامه کوتاه وجود دارد که در آن متغیرها در یک حافظه اِستک ایجاد شده اند.
      #include <stdio.h> double multiplyByTwo (double input) { double twice = input * 2.0; return twice; } int main (int argc, char *argv[]) { int age = 30; double salary = 12345.67; double myList[3] = {1.2, 2.3, 3.4}; printf("double your salary is %.3f\n", multiplyByTwo(salary)); return 0; } ما متغیر‌هایی را اعلان کرده ایم که یک int ، یک double و یک آرایه که سه نوع double دارد هستند. این متغیر‌ها داخل اِستک وارد و به زودی توسط تابع main در زمان اجرا حافظه مورد نیاز خود را دریافت خواهند کرد. زمانی که تابع main خارج می‌شود (برنامه متوقف می‌شود) این متغیر‌ها همگی از داخل حافظه اِستک خارج خواهند شد. به طور مشابه٬ در تابع multiplByTwo() متغیر twice که از نوع double است، داخل اِستک وارد شده و در زمان اجرای تابع multiplyByTwo() حافظه به آن اختصاص می‌یابد. زمانی که تابع فوق خارج شود یعنی به نقطه پایان اجرایی خود برسد، حافظه اختصاص یافته شده به متغیر‌های داخلی آن نیز آزاد خواهند شد. به طور خلاصه توجه داشته باشید که تمامی متغیر‌های محلی در این نوع تعریف تنها در طول زمان اجرایی زمانی تابع زنده هستند.
      به عنوان یک یادداشت جانبی، روشی برای نگه داری متغیر‌ها در حافظه اِستک وجود دارد، حتی در زمانی که تابع خارج می‌شود. آن روش توسط کلمه کلیدی static ممکن خواهد شد که در زمان اعلان متغیر استفاده می‌شود. متغیری که توسط کلمه کلیدی static تعریف می‌شود، بنابراین چیزی مانند متغیر از نوع سراسری خواهد بود، اما تنها در داخل تابعی که داخل آن ایجاد شده است قابل مشاهده خواهد بود. این یک ساختار عجیب و غریب است، که احتمالا به جز شرایط بسیار خاص نیازی به آن نباشد.
      نسخه دیگری از برنامه فوق در قالب حافظه هیپ به صورت زیر است:
      #include <stdio.h> #include <stdlib.h> double *multiplyByTwo (double *input) { double *twice = malloc(sizeof(double)); *twice = *input * 2.0; return twice; } int main (int argc, char *argv[]) { int *age = malloc(sizeof(int)); *age = 30; double *salary = malloc(sizeof(double)); *salary = 12345.67; double *myList = malloc(3 * sizeof(double)); myList[0] = 1.2; myList[1] = 2.3; myList[2] = 3.4; double *twiceSalary = multiplyByTwo(salary); printf("double your salary is %.3f\n", *twiceSalary); free(age); free(salary); free(myList); free(twiceSalary); return 0; } همانطور که می‌بینید، استفاده از malloc() برای تخصیص حافظه در حافظه Heap و استفاده از free() جهت آزاد سازی حافظه تخصیص یافته می‌باشد. این مواجه شدن چیز بسیار بزرگی محسوب نمی‌شود اما کمی مبهم است. چیز دیگری که باید به آن توجه داشته باشید علامت ستاره (*) است که در همه جای کد‌ها دیده می‌شود. اینها چه چیز‌هایی هستند؟ پاسخ این سوال این است : اینها اشاره گر هستند! توابع malloc() و calloc() و free() با اشاره‌گر‌هایی مواجه می‌شوند که مقادیرشان واقعی نیست. اشاره گر‌ها نوع داده ای خاصی در C هستند که آدرس حافظه مربوطه را بر می‌گردانند. در خط ۵ متغیر twice یک متغیر از نوع double نیست، اما اشاره به یک double دارد. آن آدرس حافظه ای است که نوع double در آن بلوک از حافظه ذخیره شده است.
      در ++C توسط کلمه کلیدی new که خود آن نیز یک اپراتور محسوب می‌شود می‌توان حافظه ای را در Heap اختصاص داد. به عنوان مثال:
      int* myInt = new int(256); آدرس‌های موجود در حافظه توسط اپراتور new به اشاره‌گر مربوطه پاس داده می‌شود. به مثال زیر توجه کنید٬ متغیر تعریف شده در حافظه اِستک قرار گرفته است:
      int variable = 256; سوالی که ممکن است افراد کنجکاو از خود بپرسند این است که چه زمانی از Stack و چه زمانی از Heap باید استفاده کنیم؟!
      خب پاسخ این سوال اینگونه خواهد بود٬ زمانی که شما نیاز به یک بلوک بسیار بزرگی از حافظه دارید٬ که در آن یک ساختار بزرگ یا یک ارایه بزرگی را ذخیره کنید و نیاز داشته باشید که متغیر‌های شما به مدت طولانی در سرتاسر برنامه شما در دسترس باشند در این صورت از حافظه Heap استفاده کنید.
      در صورتی که شما نیاز به متغیر‌های کوچکی دارید که تنها نیاز است در زمان اجرای تابع در دسترس باشند و قابلیت خواندن و نوشتن سریعتری داشته باشند از نوع حافظه Stack استفاده کنید. فقط فراموش نکنید که حافظه Heap تحت توابع molloc(), realloc(), calloc() و free() مدیریت می‌شوند. هرچند اشاره‌گر های هوشمند نیز در ++C وجود دارند اما در بسیاری از مواقع که نیاز است بسیار جزئی و حساس بر روی کد‌های خود کار کنید از مدیریت حافظه به صورت دستی استفاده کنید.
    • توسط فرهاد شیری
      ادامه آموزش توابع کاربردی برای برنامه نویسی سوکت...
       
      تابع bind :
      int bind( SOCKET s, const struct sockaddr FAR *name, int namelen ); این تابع وظیفه پیوند دادن اطلاعات ارتباطی (مانند آدرس) را به سوکت تعریف شده دارد ودر  برنامه سرور به کار می رود.
      آرگومان های این تابع به ترتیب زیر خواهد بود...
       آرگومان اول که متغیر نوع سوکت تعریف شده در برنامه است که با مقدار برگشتی تابع socket مقدار دهی شده است.
      آرگومان دوم آدرس محلی از حافظه است که متغیر ساختمان sockaddr_in در آنجا تعریف شده است (شرح این ساختمان در ادامه درج شده است.)
      آرگومان سوم هم اندازه متغیر ساختمان sockaddr_in است که می توانید با عملگر sizeof اندازه آن را بدست آورید.
      این تابع در صورت موفقیت مقدار صفر را بر می گرداند و در صورت عدم موفقیت SOCKET_ERROR را بر می گرداند.
       
      ساختمان داده ای sockAddr_in یک structure تعریف شده در هدر winsock.h است که محل نگه داری شماره پورت ارتباط و همچنین آدرس IP و دیگر اطلاعات است.
      struct sockaddr_in{ short sin_family, unsigned short sin_port, struct in_addr sin_addr, char sin_zero[8] }; عضوی به نام sin_family برای نگه داری نوع آدرس ارتباطی است که برای کاربرد های اینترنتی برابر ثابت AF_INET است.
      عضو sin_port مشخص کننده شماره پورت ارتباطی است.
      تابع تبدیل کننده htons(int portNumer)
      برای تبدیل عدد به نوع قابل فهم (BE1 to LE2) توسط ساختمان از تابع فوق استفاده می شود.
      و عضو sin_addr که خود یک ساختمان می باشد برای نگه داری آدرس IP که به صورت یک رشته کاراکتر مشخص می شود می باشد
      تابع تبدیل کننده inet_addr(char *ipaddress)
      برای تبدیل رشته کاراکتری که معرف آدرس IP است به نوع قابل فهم برای ساختمان داده از تابع فوق استفاده می کنیم.
      مثال کاربردی :
      sockaddr_in recSinIP; recSinIP.sin_family = AF_INET ;//set address family recSinIP.sin_port = htons(1362);//set port number recSinIP.sin_addr.S_un.s_addr = inet_addr("192.168.0.1"); نکته فنی :
      توجه داشته باشید که طبق تعاریف شبکه مقدار حداکثری تعریف پورت می تواند 65555 می باشد. که از این مقدار 1024 پورت اول توسط لایه های شبکه رزرو شده اند بنابراین شما نمی توانید از آنها استفاده نمایید.
      مانند پورت 80 که مختص به پروتکل HTTP می باشد.
      تابع listen :
      int listen( SOCKET s, int backlog ); تابع listen وظیفه گوش دادن به خط را در برنامه سرور به عهده دارد توجه داشته باشید که این تابع فقط در برنامه سرور کاربرد دارد.
      شرح آرگومان ها:
      آرگومان اول S که متغیر سوکت تعریف شده در برنامه می باشد.
      آرگومان دوم backlog هم تعداد صف های درخواستی است که به سیستم در یک زمان درخواست ارتباط داده اند و سیستم می تواند آنها را به حالت معلق نگه دارد این آرگومان می تواند برابر ثابت SOMAXCONN باشد.
      این تابع در صورت موفقیت صفر و درصورت بروز خطا ثابتی برابر با SOCKET_ERROR  را برمی گرداند.
       
      تابع accept :
      SOCKET accept( SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen ); این تابع برای قبول درخواست اتصال بعد از تابع listen استفاده می شود.
      آرگومان های این تابع مانند تابع bind می باشد با این تفاوت که در آرگومان addr مشخصات ماشین متصل شده به سرور قرار می گیرد.
      آرگومان addrlen اندازه ساختمانی که این اطلاعات را نگهداری می کنند را مشخص می کند.
      این تابع در صورت موفقیت مقدار برگشتیش توصیفات مربوط به سوکت ماشین راه دور مورد نظر ماست و در صورت بروز خطا ثابتی به نام INVALID_SOCKET را بر می گرداند.
       
      تابع connect :
       
      int connect( SOCKET s, const struct sockaddr FAR *name, int namelen ); تابع connect وظیفه برقراری ارتباط را با برنامه سرور بر عهده دارد و آرگومان های آن به شرح زیر می باشد:
      آرگومان اول s که از نوع سوکت می باشد وهمان مقدار برگشتی تابع socket می باشد.
      آرگومان دوم هم که از نوع sockAddr_in  می باشد.
      و آرگومان آخر تابع connect یعنی namelen اندازه ساختمان داده sockaddr_in است که می توان به جا مقدار آن نوشت :
      sizeof(sockaddr_in) این تابع در صورت موفقیت مقدار صفر و در صورت بروز خطا ثابتی برابر با SOCKET_ERROR را بر می گرداند.
      نکته فنی :
      همانطور که میدانید در کامپیوتر های امروزی کلمات در حافظه به صورت (LE(Little Endian ذخیره می شوند، یعنی بایت کم ارزش تر در خانه با شماره کوچکتر ذخیره می شود و بایت با ارزشتر در خانه با شماره بزرگتر ذخیره می شود.
      مثلا برای عدد هگز 3578H بایت کم ارزشتر برابر 78 وبایت پرارزشتر برابر عدد 35 است وترتیب قرار گرفتن آنها در حافظه به صورت زیر می باشد:
      خانه 89:35 خانه 89:34 خانه 89:33 خانه 89:32 همانطور که مشاهده میکنید بایت کم ارزشتر در آدرس 89:33 ذخیره شده و بایت با ارزشتر در خانه 89:34 ذخیره شده است کامپیوترهای معمول بدین صورت کلمات را در حافظه ذخیره میکنند اما در پشته TCP/IP به صورت عکس عمل می شوند یعنی از نوع (BE(Big Endian پشتیبانی می شود به بیان دقیق تر باید ترتیب بایت ها در حافظه درست باشد یعنی بایت با ارزشتر در آدرس کوچکتر و بایت کم ارزشتر در آدرس بزرگترذخیره شود مثلا برای عدد 3578H مانند شکل زیر عمل می شود:
      خانه 89:32 خانه 89:33 خانه 89:34 خانه 89:35 البته باید توجه داشته باشید که فقط ما باید ورودی های هدر TCP/IP را به نوع (BE(Big Endian تبدیل کنیم یعنی آدرس IP و شماره پورت وکلا اطلاعاتی که تحت شبکه ارسال می شوند. دیگر ثوابت به طور خودکار در تمامی کامپیوترها به صورت صحیح قرار دارند و دیگری نیازی به تنظیم ما ندارند.
      //برمی گرداند BE این تابع آرگومان خود را که یک عدد دوبایتی است به حالت u_short htons( u_short hostshort ); //برمی گرداند BE این تابع آرگومان خود را که یک عدد چهار بایتی است را به حالت u_long htonl( u_long hostlong ); //برمی گرداند LE این تابع آرگومان خود را که یک عدد دوبایتی است به حالت u_short ntohs( u_short netshort ); //برمی گرداند LE این تابع آرگومان خود را که یک عدد چهار بایتی است را به حالت u_long ntohl( u_long netlong ); //که معرف آدرس آی پی است را دریافت میکند ویک عدد چهار بایتی (a.b.c.d)این تابع یک رشته کاراکتر //بر می گرداند در صورتی که آدرس آی پی نامعتبر باشد یا تابع عملیات خود را با موقیت انجام BE از نوع //توسط تابع برگردانده می شود INADDR_NONE ندهد ثابت unsigned long int inet_addr( const char FAR *cp )  
       
      همچنان ادامه خواهد داشت...
    • توسط فرهاد شیری
      با سلام
      هدف من از تهیه این آموزش شناخت کلی درباره (Socket Programming) که بسیار وسیع هست، والبته برای خیلی از برنامه نویسها هم همیشه جذاب بوده که بتوانند برنامه های تحت شبکه بنویسند بوده است.
      و از آنجاییکه با فراگیری برنامه نویسی سوکت در زبان C قادر خواهید بود، برنامه هایی در زمینه های بسیار تخصصی مانند (Intrusion Detect system) سیستم های تست نفوذ، ابزارهای (sniff) تحت نظرقرار دادن پکت ها، تا برنامه های ساده ای مانند چت و نمایش فیلم های آنلاین و خرید های مجازی و ... را انجام دهید.
      البته ما دراین آموزش سعی بر آن خواهیم داشت که بیشتر به نکات کاربردی درباره سوکت، که اغلب خود من از آنها در پروژه هایم استفاده کرده ام اشاره داشته باشیم.
      سوکت (Socket) چیست؟
      با یک بیان ساده می توان گفت که سوکت به ترتیب یک آدرس ماشین IP ویک شماره درگاه Port گفته می شود.
      در برقراری ارتباط بین کامپیوترها در یک شبکه دوچیز بسیار مهم است.
      1- آدرس ماشینی که می خواهیم اطلاعاتی از آن بگیریم ویا به آن ارسال کنیم.
      2- برنامه ای از آن ماشین که در خواست اطلاعات کرده یا اینکه می خواهیم اطلاعاتی از آن برنامه کسب کنیم این دو یعنی آدرس ماشین وشماره برنامه به وسیله سوکت در شبکه مشخص می شوند.
      WinSock چیست؟
      Winsock یا Windows Socket یک رویه (Interface) برنامه نویسی است که در غالب یک DLL در سیستم عامل ویندوز برای برنامه نویسی شبکه و ساخت برنامه هایی که بتوانند با شبکه محاوره داشته باشند معرفی شده است.
      ارتباط مابین دوکامپیوتر می تواند به یکی از دوصورت زیر باشد:
      - اتصال گرا (Connection Oriented)
      - غیر اتصال گرا (Connection Less)
      در سیستم اتصال گرا ابتدا درخواست اتصال ارسال شده و درصورت موافقت طرف مقابل ارتباط برقرار می شود.به این تکنیک 
      Data Stream نیز گفته می شود.
      اما در سیستم غیر اتصال گرا بدون نیاز به موافقت طرف مقابل بسته ها ارسال می شوند به این تکنیک Data Gram نیز
      می گویند.
      TCP/UDP :
      در پشته پروتکلی TCP/IP دونوع ارتباط می توان با کامپیوتر دور ایجاد کرد:
      - اتصال به کامپیوتر راه دور به وسیله سوکت Data Stream.
      - اتصال به کامپیوتر راه دور به وسیله سوکت Data Gram.
      به طورخلاصه به نوع ارتباط اول (اتصال گرا) ارتباط از نوع TCP گفته می شود. واگر نوع برقراری ارتباط به حالت
      (غیر اتصال گرا ) باشد به آن UDP گفته می شود.
      دوستان بهتره هست قبلا حتما مدل مرجع OSI برای شناخت بهتر لایه های شبکه را مطالعه نمایید. به علت مباحث تکنیکی و کمی هم پیچیده مدل OSI ما در این آموزش وارد جزئیات نخواهیم شد. تحقیق درباره آن را به خودتون واگذار میکنم.
      معرفی توابع مهم مورد استفاده در برنامه نویسی TCPIP با زبان C
      کتابخانه کار با سوکت های در زبان C می تواند از سیستم عاملی به سیستم عاملی دیگر متفاوت باشد. همینطور از سخت افزاری به سخت افزاری دیگر به عنوان مثال برای برنامه نویسی شبکه در سیستم عامل ویندوز ما از هدر فایل winsock2.h استفاده می کنیم که خود نگارشهای مختلفی دارد وبرای برنامه نویسی شبکه در سیستم عامل های خانواده NIX* از هدر فایل sys/socket.h , sys/type.h و هدرهای دیگر استفاده می کنیم که البته می توان با اقدامی هوشمندانه توسط راهنمای کامپایلر نوع سیستم عامل را تشخیص داد وبعد هدر های مربوط به هر سیستم عامل را مورد استفاده قرارداد.
      البته باید عرض کنم که توابع مورد استفاده در همه انواع هدرها یکسان می باشند، مگر در معدود مواردی که هر کجا احساس نیاز شود ذکر خواهند شد.
      شرح توابع مهم موجود در هدر فایل winsock2.h 
      int WSAStartup( WORD wVersionRequested , LPWSADATA lpWSAData ); این تابع برای آماده سازی و بار گذاری اولیه سیستم عامل برای اجرای برنامه تحت شبکه می باشد.
      آرگومان های آن عبارتند از :
      wVersionRequested شماره نگارش هدر winsock.h است که برای تبدیل این شماره به نوع WORD می توان از ماکرو makeword استفاده کرد.
      نکته فنی :
      به هر 4 بیت یک NIBBLE گفته می شود. وبه هر 8 بیت یک BYTE گفته می شود. وبه هر 16 بیت یا دو بایت یک WORD گفته می شود.
      به عنوان مثال :
      WORD wVersionRequested=makeword(2,0); winsock1.1.h و برای نگارش WORD wVersionRequested=makeword(2,1); و آرگومان دوم یک متغیر از نوع ساختمان داده ای WSADATA می باشد که در هدر winsock تعریف شده است.
      اعضای این ساختمان و نحوه تعریف آن به این صورت است:
      typedef struct WSAData{ WORD wVersion; WORD wHighVersion; char szDescription[WSADESCRIPTION_LEN+1]; char szSystemStatus[WSASYS_STATUS_LEN+1]; unsigned short iMaxSockets; unsigned short iMaxUdpDg; char FAR* lpVendorInfo; } WSADATA , *LPWSADATA; مثال کاربرد :
      WSADATA wsaData; WORD wVersionRequested=makeword(2,0); WSAStatrtup(wVersionRequested,wsaData); این تابع در صورت موفقیت مقدار صفر را بر می گرداند و در صورت شکست کد خطای رخ داده را بر می گرداند.
      int WSACleanup(void); از این تابع برای اتمام بارگذاری مربوط به شکست سیستم عامل استفاده می شود. این تابع در صورت موفقیت مقدار صفر و در صورت بروز خطا ثابتی برابر با SOCKET_ERROR را برمی گرداند.
      تابع socket :
      SOCKET socket( int af, int type, int protocol );  از تابع فوق برای تعریف وایجاد یک پورت استفاده می کنیم .و مقدار برگشتی آن توصیف کننده پورت مورد نظر است آرگومانهای تابع به ترتیب از این قرار هستند:
      af - مشخص کننده نوع آدرس است که برای کاربری اینترنت برابر ثابت AF_INET است برای کنترل سوکت ها در یونیکس برابر ثابت AF_UNIX است و مقادیر دیگر...
      type - مشخص کننده نوع ارتباطها می باشد که برای ارتباط TCP ثابت SOCK_STREAM و برای یک ارتباط UDP برابر SOCK_DGRAM است.
      protocol - هم نماینگر نوع پروتکل انتخابی ماست برای یک ارتباط TCP برابر با ثابت IPPROTO_TCP  یا مقدار عددی 0 وبرای UDP مقدار عددی 1 یا ثابت IPPROTO_UDP می باشد.
      این تابع در صورت موفقیت مقدار برگشتی اش توصیفات مربوط به سوکت مورد نظر ماست و در صورت بروز خطا ثابتی به نام INVALID_SOCKET را بر می گرداند.
      ادامه دارد...
    • توسط GornerLabo
      سلام خدمت اساتید محترم . در مورد qint64 میخواستم اطلاعاتی کسب کنم. برای چه مواردی در برنامه نویسی با Qt استفاده می شود ؟
      با تشکر.
    • توسط فرهاد شیری
      کلاس Single Tone ژنریک با استفاده از اشاره گرهای هوشمند برای ساخت آبجکتی از یک کلاس با یک نمونه واحد برای صرفه جویی در حافظه مصرفی
      #ifndef SINGLETON_H #define SINGLETON_H #include <memory> namespace BP { template<typename CL> class SingleTone { protected: SingleTone() = default; // defualt ctor virtual inline ~SingleTone(){ delete instance; } private: static CL* instance; SingleTone(const SingleTone&) = delete; //copy ctor SingleTone(SingleTone&&) = delete ; //move ctor SingleTone& operator=(const SingleTone&) =delete ; // copy oprator assignment SingleTone& operator=(SingleTone&&) =delete ; // move oprator assignment static void destory(CL* my){ delete my ; instance = NULL; } public: std::unique_ptr<CL , decltype(&destory)> factory(){ //lazy instation if(instance == NULL){ instance = new CL(); } return std::unique_ptr<CL , decltype(&destory)>(instance , &destory); } }; template<typename CL> CL* SingleTone<CL>::instance = NULL; } #endif // SINGLETON_H ونحوه استفاده از کلاس فوق من کلاسی دارم برای ارتباط با پایگاه داده به نام DBProvider که در این کلاس متدی به نام OpenConnection را صدا زدم.
      توجه کنید که هر کلاسی که بخواهید را می توانید به حالت single tone ایجاد نمایید.
      روش اول فراخوانی
      db = SingleTone<DBProvider>::factory ()->OpenConnection () روش دوم فراخوانی
      db = (*SingleTone<DBProvider>::factory ()).OpenConnection (); فقط توجه داشته باشید که آبجکتهایی که single tone هستند یک اشاره گر واحد دارند بنابراین در کل برنامه یکسان خواهند بود.
×