আগে বা লুপে ভেরিয়েবল ঘোষণার মধ্যে পার্থক্য?


312

আমি সর্বদা ভাবছি যে, সাধারণভাবে, একটি লুপের আগে একটি বার বার থ্রো-অ্যাওর ভেরিয়েবল ঘোষণা করে, লুপের ভিতরে বারবার বিপরীতে, কোনও (পারফরম্যান্স) পার্থক্য করে? জাভাতে একটি (যথেষ্ট অর্থহীন) উদাহরণ:

ক) লুপের আগে ঘোষণা:

double intermediateResult;
for(int i=0; i < 1000; i++){
    intermediateResult = i;
    System.out.println(intermediateResult);
}

খ) ঘোষণা (বারবার) লুপ ভিতরে:

for(int i=0; i < 1000; i++){
    double intermediateResult = i;
    System.out.println(intermediateResult);
}

কোনটি ভাল, বা ?

আমার সন্দেহ হয় যে বারবার পরিবর্তনশীল ঘোষণাপত্র (উদাহরণ ) তত্ত্বে আরও ওভারহেড তৈরি করে , তবে সেই সংকলকগুলি যথেষ্ট স্মার্ট যাতে এটি কোনও ব্যাপার না। উদাহরণ বি এর আরও কমপ্যাক্ট হওয়ার সুবিধা রয়েছে এবং ভেরিয়েবলের সুযোগটি যেখানে ব্যবহৃত হয় তা সীমাবদ্ধ রাখার সুবিধা রয়েছে। তবুও, আমি উদাহরণ হিসাবে কোড প্রবণতা

সম্পাদনা: আমি জাভা ক্ষেত্রে বিশেষভাবে আগ্রহী।


অ্যান্ড্রয়েড প্ল্যাটফর্মের জন্য জাভা কোড লেখার সময় এটি গুরুত্বপূর্ণ। গুগল পরামর্শ দিয়েছে যে টাইম-ক্রিটিকাল কোডের জন্য ফর-লুপের বাইরে ইনক্রিমেন্টিং ভেরিয়েবলগুলি ঘোষণা করার জন্য, যেন লুপের ভিতরে, এটি সেই পরিবেশে প্রতিবার এটি পুনরায় ঘোষণা করে। ব্যয়বহুল অ্যালগরিদমের জন্য পারফরম্যান্সের পার্থক্যটি খুব লক্ষণীয়।
অ্যারোনকারসন

1
অ্যারোন কারসন আপনি কি গুগলের এই পরামর্শটির লিঙ্কটি সরবরাহ করতে পারেন
ভাইটালি জিংচেঙ্কো

উত্তর:


256

কোনটি ভাল, বা ?

পারফরম্যান্সের দৃষ্টিকোণ থেকে আপনাকে এটি পরিমাপ করতে হবে। (এবং আমার মতে, আপনি যদি কোনও পার্থক্য পরিমাপ করতে পারেন তবে সংকলকটি খুব ভাল নয়)।

রক্ষণাবেক্ষণের দৃষ্টিকোণ থেকে আরও ভাল। সম্ভব সংকীর্ণ সুযোগে একই জায়গায় ভেরিয়েবলগুলি ঘোষণা এবং প্রারম্ভিক করুন। ঘোষণা এবং প্রারম্ভিককরণের মধ্যে কোনও ফাঁক গর্ত ছেড়ে যাবেন না এবং আপনার যে নেমস্পেসের প্রয়োজন নেই সেগুলি দূষিত করবেন না।


5
ডাবলের পরিবর্তে, যদি এটি স্ট্রিংয়ের সাথে সম্পর্কিত হয়, তবে কি "বি" কেস ভাল?
12

3
@ এন্টোপস - হ্যাঁ, বি এর কারণে ভেরিয়েবলের ডেটা টাইপের কোনও সম্পর্ক নেই বলেই ভাল। স্ট্রিংসের জন্য কেন এটি আলাদা হবে?
ড্যানিয়েল আরউইকার

দ্বিতীয় অনুচ্ছেদের জন্য একটি
উত্সাহ

215

ভাল আমি 100 মিলিয়ন বার লুপ করে প্রতিবার 20 বার আপনার এ এবং বি উদাহরণ রেখেছি ((জেভিএম - 1.5%)

উ: গড় কার্যকর সময়: .074 সেকেন্ড

বি: গড় কার্যকর সময়: .067 সেকেন্ড

আমার অবাক বি কিছুটা দ্রুত ছিল। কম্পিউটারগুলি এখন যত দ্রুত ততই বলা শক্ত যে আপনি এটি সঠিকভাবে পরিমাপ করতে পারতেন কিনা say আমি এটিকেও একটি উপায় হিসাবে কোড করব তবে আমি বলব এটি সত্যিই কিছু যায় আসে না।


12
আপনি আমাকে মারলেন আমি প্রোফাইলের জন্য আমার ফলাফল পোস্ট করতে যাচ্ছিলাম, আমি কমবেশি একই রকম পেয়েছি এবং হ্যাঁ আশ্চর্যজনকভাবে বি দ্রুততর সত্যিই আমার যদি এটির উপর বাজি রাখার দরকার হয় তবে ভাবতেন।
মার্ক ডেভিডসন

14
খুব অবাক হওয়ার কিছু নেই - যখন ভেরিয়েবল লুপের স্থানীয় হয়, প্রতিটি পুনরুক্তির পরে এটি সংরক্ষণ করার প্রয়োজন হয় না, তাই এটি কোনও নিবন্ধেই থাকতে পারে।

142
এটি পরীক্ষার জন্য +1 , কেবল কোনও মতামত / তত্ত্বই নয় যে ওপি নিজেকে তৈরি করতে পারে।
MGOwen

3
@ গুডপারসন সত্যি বলতে, আমি এটি সম্পন্ন করতে চাই like আমি প্রায় 10 বার আমার মেশিনে প্রায় 50,000,000-100,000,000 পুনরাবৃত্তির জন্য এই যন্ত্রটি প্রায় এক অভিন্ন টুকরো কোড সহ চালিয়েছি (যে আমি যে কেউ স্ট্যাটাস চালাতে চায় তার সাথে ভাগ করে নিতে চাই)। উত্তরগুলি প্রায় সমানভাবেই প্রায় 900 মিমি (50M এর বেশি পুনরাবৃত্তির) ব্যবধানে বিভক্ত হয়েছিল যা আসলে খুব বেশি নয়। যদিও আমার প্রথম ধারণা এটি "শব্দ" হতে চলেছে, এটি কিছুটা ঝুঁকতে পারে। এই প্রচেষ্টাটি আমার কাছে নিখুঁতভাবে একাডেমিক বলে মনে হচ্ছে (বেশিরভাগ বাস্তব জীবনের অ্যাপ্লিকেশনগুলির জন্য) .. আমি যাইহোক ফলাফল দেখতে পছন্দ করব;) যে কেউ রাজি হন?
জাভাতারz

3
সেটআপের নথিপত্র না দিয়ে পরীক্ষার ফলাফল প্রদর্শন করা নিরর্থক। এটি এই ক্ষেত্রে বিশেষত সত্য, যেখানে উভয় কোড টুকরাই অভিন্ন বাইকোড তৈরি করে, তাই কোনও পরিমাপ করা পার্থক্য কেবলমাত্র অপ্রতুল পরীক্ষার শর্তগুলির একটি চিহ্ন।
হলগার

66

এটি ভাষা এবং সঠিক ব্যবহারের উপর নির্ভর করে। উদাহরণস্বরূপ, সি # 1 এ এটি কোনও পার্থক্য করে না। সি # 2-তে, যদি স্থানীয় ভেরিয়েবল একটি বেনাম পদ্ধতি (বা সি # 3-এ ল্যাম্বডা এক্সপ্রেশন) দ্বারা ক্যাপচার করা হয় তবে এটি খুব লক্ষণীয় পার্থক্য করতে পারে।

উদাহরণ:

using System;
using System.Collections.Generic;

class Test
{
    static void Main()
    {
        List<Action> actions = new List<Action>();

        int outer;
        for (int i=0; i < 10; i++)
        {
            outer = i;
            int inner = i;
            actions.Add(() => Console.WriteLine("Inner={0}, Outer={1}", inner, outer));
        }

        foreach (Action action in actions)
        {
            action();
        }
    }
}

আউটপুট:

Inner=0, Outer=9
Inner=1, Outer=9
Inner=2, Outer=9
Inner=3, Outer=9
Inner=4, Outer=9
Inner=5, Outer=9
Inner=6, Outer=9
Inner=7, Outer=9
Inner=8, Outer=9
Inner=9, Outer=9

পার্থক্যটি হ'ল সমস্ত ক্রিয়া একই outerভেরিয়েবল ক্যাপচার করে তবে প্রত্যেকটির নিজস্ব আলাদা innerভেরিয়েবল থাকে।


3
উদাহরণস্বরূপ বি (মূল প্রশ্ন), এটি কি প্রতিবারই আসলে নতুন পরিবর্তনশীল তৈরি করে? স্ট্যাকের চোখে কী হচ্ছে?
রই নমির

@ জন, এটি কি সি # 1.0 এ বাগ ছিল? আদর্শ Outer9 হওয়া উচিত নয় ?
নওফাল

@ নওফাল: আপনার অর্থ কী তা আমি জানি না। ল্যামডা এক্সপ্রেশন 1.0 ছিল না ... আর বাইরের হয় 9. আপনি কী বাগ মানে কী?
জন স্কিটি

@ নওফাল: আমার বক্তব্যটি হ'ল সি # 1.0 তে কোনও ভাষার বৈশিষ্ট্য নেই যেখানে আপনি একটি লুপের ভিতরে ভেরিয়েবল ঘোষণা করা এবং এটি বাইরে ঘোষণার মধ্যে পার্থক্য বলতে পারতেন (ধরে নিলেন উভয় সংকলিত)। এটি সি # 2.0 তে পরিবর্তিত হয়েছে। কোনও বাগ নেই।
জন স্কেটি

@ জোনস্কিট ওহ হ্যাঁ, আমি আপনাকে এখনই পেয়েছি, আমি পুরোপুরি এড়িয়ে গিয়েছি যে আপনি 1.0 এর মতো ভেরিয়েবলগুলি বন্ধ করতে পারবেন না, আমার খারাপ! :)
নওফাল

35

নীচে আমি .NET লিখেছিলাম এবং সংকলন করেছি।

double r0;
for (int i = 0; i < 1000; i++) {
    r0 = i*i;
    Console.WriteLine(r0);
}

for (int j = 0; j < 1000; j++) {
    double r1 = j*j;
    Console.WriteLine(r1);
}

এই আমি থেকে পেতে হয় .NET প্রতিফলক যখন CIL কোড ফিরে অনুষ্ঠিত হয়।

for (int i = 0; i < 0x3e8; i++)
{
    double r0 = i * i;
    Console.WriteLine(r0);
}
for (int j = 0; j < 0x3e8; j++)
{
    double r1 = j * j;
    Console.WriteLine(r1);
}

তাই উভয় সংকলনের পরে একেবারে একই দেখতে। পরিচালিত ভাষাগুলিতে কোডটি সিএল / বাইট কোডে রূপান্তরিত হয় এবং সম্পাদনের সময় এটি মেশিনের ভাষায় রূপান্তরিত হয়। সুতরাং মেশিনের ভাষায় স্ট্যাকের উপরে একটি ডাবল তৈরিও করা যায় না। কোডটি প্রতিবিম্বিত হিসাবে এটি কেবল একটি নিবন্ধ হতে পারে যে এটি এর জন্য একটি অস্থায়ী পরিবর্তনশীলWriteLine ফাংশনের । কেবল লুপগুলির জন্য একটি সম্পূর্ণ সেট অপ্টিমাইজেশন বিধি রয়েছে। সুতরাং গড়পড়তা লোকটিকে এটি নিয়ে উদ্বিগ্ন হওয়া উচিত নয়, বিশেষত পরিচালিত ভাষাগুলিতে। এমন কিছু ক্ষেত্রে রয়েছে যখন আপনি কোড পরিচালনা করতে পারেন, উদাহরণস্বরূপ, যদি আপনাকে কেবল string a; a+=anotherstring[i]বনাম ব্যবহার করে প্রচুর পরিমাণে স্ট্রিং যুক্ত করতে হয়StringBuilder। উভয়ের মধ্যে পারফরম্যান্সে খুব বড় পার্থক্য রয়েছে। এমন অনেকগুলি কেস রয়েছে যেখানে সংকলকটি আপনার কোডটি অনুকূলিত করতে পারে না, কারণ এটি কোনও বৃহত্তর স্কোপের উদ্দেশ্য কী তা নির্ধারণ করতে পারে না। তবে এটি আপনার জন্য মৌলিক বিষয়গুলিকে আরও অনেক অনুকূল করতে পারে।


(; j <0x3e8; j ++) এর জন্য int j = 0 এভাবে একবারে উভয় পরিবর্তনশীল হিসাবে ঘোষিত, এবং প্রতিটি চক্রের জন্য নয়। 2) অ্যাসাইনমেন্টটি এটি অন্যান্য বিকল্পের চেয়ে বেশি চর্বিযুক্ত। 3) সুতরাং সেরা অনুশীলনের নিয়ম হল এর জন্য পুনরাবৃত্তির বাইরে কোনও ঘোষণা।
লুকা

24

এটি ভিবি.এনইটি-তে একটি গোটচা। ভিজ্যুয়াল বেসিক ফলাফলটি এই উদাহরণে পরিবর্তনশীলটিকে পুনরায়ায়ন করতে পারে না:

For i as Integer = 1 to 100
    Dim j as Integer
    Console.WriteLine(j)
    j = i
Next

' Output: 0 1 2 3 4...

এটি প্রথমবার 0 টি মুদ্রণ করবে (ভিজ্যুয়াল বেসিক ভেরিয়েবলগুলির ঘোষণার সময় ডিফল্ট মান থাকে!) তবে তার iপরে প্রতিটি সময়।

আপনি যদি একটি যোগ করেন = 0তবে আপনি যা আশা করতে পারেন তা পেতে পারেন:

For i as Integer = 1 to 100
    Dim j as Integer = 0
    Console.WriteLine(j)
    j = i
Next

'Output: 0 0 0 0 0...

1
আমি বছরের পর বছর ধরে ভিবি.এনইটি ব্যবহার করে আসছি এবং এগুলি আসেনি!
ক্রিসএ

12
হ্যাঁ, বাস্তবে এটি নির্ধারণ করা অপ্রীতিকর।
মাইকেল হরেন

: এখানে পল ভিক থেকে এই সম্পর্কে একটি রেফারেন্স panopticoncentral.net/archive/2006/03/28/11552.aspx
ferventcoder

1
@ ইশনিদার @ স্পারভেন্টকোডার দুর্ভাগ্যক্রমে @ পলভ তার পুরানো ব্লগ পোস্টগুলি ফেলে দেওয়ার সিদ্ধান্ত নিয়েছে , সুতরাং এটি এখন একটি মৃত লিঙ্ক।
মার্ক হার্ট

হ্যাঁ, সম্প্রতি এই জুড়ে দৌড়ে; এটি সম্পর্কে কিছু অফিসিয়াল ডক্স খুঁজছিল ...
এরিক স্নাইডার

15

আমি একটি সাধারণ পরীক্ষা করেছি:

int b;
for (int i = 0; i < 10; i++) {
    b = i;
}

বনাম

for (int i = 0; i < 10; i++) {
    int b = i;
}

আমি জিসিসি - 5.2.0 সহ এই কোডগুলি সংকলন করেছি। এবং তারপরে আমি এই দুটি কোডের মূল () পৃথক করেছিলাম এবং এর ফলাফল:

1º:

   0x00000000004004b6 <+0>:     push   rbp
   0x00000000004004b7 <+1>:     mov    rbp,rsp
   0x00000000004004ba <+4>:     mov    DWORD PTR [rbp-0x4],0x0
   0x00000000004004c1 <+11>:    jmp    0x4004cd <main+23>
   0x00000000004004c3 <+13>:    mov    eax,DWORD PTR [rbp-0x4]
   0x00000000004004c6 <+16>:    mov    DWORD PTR [rbp-0x8],eax
   0x00000000004004c9 <+19>:    add    DWORD PTR [rbp-0x4],0x1
   0x00000000004004cd <+23>:    cmp    DWORD PTR [rbp-0x4],0x9
   0x00000000004004d1 <+27>:    jle    0x4004c3 <main+13>
   0x00000000004004d3 <+29>:    mov    eax,0x0
   0x00000000004004d8 <+34>:    pop    rbp
   0x00000000004004d9 <+35>:    ret

বনাম

   0x00000000004004b6 <+0>: push   rbp
   0x00000000004004b7 <+1>: mov    rbp,rsp
   0x00000000004004ba <+4>: mov    DWORD PTR [rbp-0x4],0x0
   0x00000000004004c1 <+11>:    jmp    0x4004cd <main+23>
   0x00000000004004c3 <+13>:    mov    eax,DWORD PTR [rbp-0x4]
   0x00000000004004c6 <+16>:    mov    DWORD PTR [rbp-0x8],eax
   0x00000000004004c9 <+19>:    add    DWORD PTR [rbp-0x4],0x1
   0x00000000004004cd <+23>:    cmp    DWORD PTR [rbp-0x4],0x9
   0x00000000004004d1 <+27>:    jle    0x4004c3 <main+13>
   0x00000000004004d3 <+29>:    mov    eax,0x0
   0x00000000004004d8 <+34>:    pop    rbp
   0x00000000004004d9 <+35>:    ret 

যা একই asm ফলাফল exaclty হয়। দুটি কোড একই জিনিস উত্পাদন করে এমন কোনও প্রমাণ নয়?


3
হ্যাঁ, এবং এটি দুর্দান্ত যে আপনি এটি করেছিলেন, তবে ভাষা / সংকলক নির্ভরতা সম্পর্কে লোকেরা যা বলছিল তা এখানে ফিরে আসে। আমি ভাবছি কীভাবে জেআইটি বা ব্যাখ্যা করা ভাষার পারফরম্যান্স প্রভাবিত হবে।
ব্যবহারকারী 137717

12

এটি ভাষা নির্ভর


হ্যাঁ, তবে এর পরিমাণ খুব একটা নয়। আমি লুপের জন্য 100 মিলিয়ন বার কার্যকর করার জন্য একটি সহজ পরীক্ষা চালিয়েছি এবং আমি দেখতে পেয়েছি যে লুপের বাইরে ঘোষণার পক্ষে সবচেয়ে বড় পার্থক্যটি ছিল 8 এমএস। এটি সাধারণত 3-4-এর মতো ছিল এবং মাঝে মাঝে লুপের বাইরে ডাব্লু ওয়ার্ল্ড (4 এমএস পর্যন্ত) ঘোষণা করে, তবে এটি সাধারণ ছিল না।
ব্যবহারকারী 137717

11

আমি সর্বদা একটি ব্যবহার করব (সংকলকের উপর নির্ভর করার চেয়ে) এবং আবারও লিখতে পারি:

for(int i=0, double intermediateResult=0; i<1000; i++){
    intermediateResult = i;
    System.out.println(intermediateResult);
}

এটি এখনও intermediateResultলুপের স্কোপকে সীমাবদ্ধ করে তবে প্রতিটি পুনরাবৃত্তির সময় পুনরায় ঘোষনা করে না।


12
আপনি কি বৈকল্পিকভাবে পৃথক পৃথক পুনরাবৃত্তির পরিবর্তে লুপের সময়কালের জন্য বেঁচে থাকতে চান? আমি খুব কমই করি। কোড লিখুন যা আপনার উদ্দেশ্যটি যতটা সম্ভব স্পষ্টভাবে প্রকাশ করে, যদি না আপনি অন্যথায় করণটির খুব, খুব ভাল কারণ না পেয়ে থাকেন।
জন স্কিটি

4
আহ, সুন্দর আপোস, আমি কখনই এ নিয়ে ভাবি নি! আইএমও, কোডটি যদিও কিছুটা কম দৃষ্টিশক্তিভাবে পরিষ্কার হয়ে যায়)
রবিড্রেস্কি

2
@ জন - মাঝারি মানের সাথে ওপি আসলে কী করছে তা আমার কোনও ধারণা নেই। এটি ভেবে দেখেছি এটি বিবেচনার মতো একটি বিকল্প।
ট্রিপটিচ

6

আমার মতে, বি আরও ভাল কাঠামো। একটিতে, আপনার লুপ শেষ হওয়ার পরে ইন্টারমিডিয়েটরিসাল্টের সর্বশেষ মানটি আটকে যায়।

সম্পাদনা করুন: এটি মান ধরণের সাথে খুব বেশি পার্থক্য করে না, তবে রেফারেন্সের প্রকারগুলি কিছুটা ভারী হতে পারে। ব্যক্তিগতভাবে, আমি পরিষ্কারের জন্য যত তাড়াতাড়ি সম্ভব ভেরিয়েবলগুলি যথাযথভাবে পছন্দ করা পছন্দ করি এবং খ তা আপনার জন্য করে,


sticks around after your loop is finished- যদিও এটি পাইথনের মতো ভাষায় কিছু যায় আসে না, যেখানে ফাংশন শেষ হওয়া অবধি বেঁধে দেওয়া নামগুলি আটকে থাকে।
new123456

@ new123456: ওপি জাভা সুনির্দিষ্ট চাইলেন, এমনকি যদি প্রশ্ন করা হয় কিছুটা জেনেরিক জিজ্ঞাসা। অনেক সি-উত্পন্ন ভাষাগুলিতে ব্লক-স্তরীয় স্কোপিং রয়েছে: সি, সি ++, পার্ল ( myকীওয়ার্ড সহ), সি #, এবং জাভা আমি 5 ব্যবহার করেছি।
পাওয়ারলর্ড

আমি জানি - এটি একটি পর্যবেক্ষণ ছিল, সমালোচনা নয়।
new123456

5

আমি সন্দেহ করি যে কয়েকটি সংকলক উভয়কেই একই কোড হিসাবে অনুকূলিত করতে পারে, তবে অবশ্যই সমস্ত নয় not সুতরাং আমি বলতে চাই আপনি প্রাক্তনের সাথে ভাল থাকবেন। পরেরটির একমাত্র কারণ হ'ল যদি আপনি নিশ্চিত করতে চান যে ঘোষিত ভেরিয়েবলটি কেবল আপনার লুপের মধ্যেই ব্যবহৃত হয় ।


5

একটি সাধারণ নিয়ম হিসাবে, আমি আমার পরিবর্তনগুলি অভ্যন্তরীণ-সম্ভাব্য স্কোপটিতে ঘোষণা করি। সুতরাং, যদি আপনি লুপের বাইরে ইন্টারমিডিয়েটার রেজাল্ট ব্যবহার না করেন তবে আমি বি এর সাথে যাব


5

কোনও সহকর্মী প্রথম ফর্মটি পছন্দ করে, এটিকে একটি অপ্টিমাইজেশন বলে, কোনও ঘোষণাকে পুনরায় ব্যবহার করতে পছন্দ করে।

আমি দ্বিতীয়টি পছন্দ করি (এবং আমার সহকর্মীকে রাজি করার চেষ্টা করব! ;-)) যা পড়ে:

  • এটি ভেরিয়েবলের যেখানে প্রয়োজন তাদের স্কোপ হ্রাস করে, যা একটি ভাল জিনিস।
  • পারফরম্যান্সে কোনও উল্লেখযোগ্য পার্থক্য না করার জন্য জাভা যথেষ্ট অনুকূল করে। আইআইআরসি, সম্ভবত দ্বিতীয় ফর্মটি আরও দ্রুত।

যাইহোক, এটি অসময়ে অপ্টিমাইজেশনের বিভাগে আসে যা সংকলক এবং / অথবা জেভিএম মানের উপর নির্ভর করে।


5

C # তে পার্থক্য রয়েছে যদি আপনি কোনও ল্যাম্বদা ইত্যাদিতে ভেরিয়েবলটি ব্যবহার করেন তবে সাধারণভাবে সংকলকটি মূলত একই কাজ করবে, ধরে নেওয়া যায় যে ভেরিয়েবলটি কেবল লুপের মধ্যেই ব্যবহৃত হয়।

প্রদত্ত যে তারা মূলত একই: নোট সংস্করণ বি পাঠকদের কাছে এটি আরও স্পষ্ট করে তোলে যে লুপের পরে চলকটি নয়, এবং ব্যবহার করা যায় না। অতিরিক্তভাবে, সংস্করণ বি আরও অনেক সহজে রিফ্যাক্টর। সংস্করণ এ এর ​​লুপ বডিটি নিজস্ব পদ্ধতিতে উত্তোলন করা আরও কঠিন। তদুপরি, সংস্করণ বি আপনাকে আশ্বাস দেয় যে এই ধরনের রিফ্যাক্টরিংয়ের কোনও পার্শ্ব প্রতিক্রিয়া নেই।

অতএব, সংস্করণটি আমাকে শেষ পর্যন্ত বিরক্ত করে, কারণ এর কোনও লাভ নেই এবং কোড সম্পর্কে যুক্তি যুক্তিটি আরও জটিল করে তোলে ...


5

ঠিক আছে, আপনি সর্বদা এটির জন্য সুযোগ তৈরি করতে পারেন:

{ //Or if(true) if the language doesn't support making scopes like this
    double intermediateResult;
    for (int i=0; i<1000; i++) {
        intermediateResult = i;
        System.out.println(intermediateResult);
    }
}

এইভাবে আপনি কেবল একবার ভেরিয়েবলটি ঘোষণা করেন এবং আপনি লুপটি ছেড়ে গেলে এটি মারা যায়।


4

আমি সবসময় ভেবেছিলাম যে আপনি যদি নিজের লুপের ভিতরে আপনার ভেরিয়েবলগুলি ঘোষণা করেন তবে আপনি স্মৃতি নষ্ট করছেন। আপনার যদি এরকম কিছু থাকে:

for(;;) {
  Object o = new Object();
}

তারপরে কেবল প্রতিটি পুনরাবৃত্তির জন্য অবজেক্টটি তৈরি করা প্রয়োজন তা নয়, তবে প্রতিটি বস্তুর জন্য একটি নতুন রেফারেন্সও প্রয়োজন। দেখে মনে হচ্ছে আবর্জনা সংগ্রহকারী যদি ধীর গতিতে থাকে তবে আপনার কাছে একগুচ্ছ ঝোঁকযুক্ত রেফারেন্স রয়েছে যা পরিষ্কার করা দরকার।

তবে আপনার যদি এটি থাকে:

Object o;
for(;;) {
  o = new Object();
}

তারপরে আপনি কেবলমাত্র একটি একক রেফারেন্স তৈরি করছেন এবং প্রতিবার এটিতে একটি নতুন অবজেক্ট বরাদ্দ করছেন। অবশ্যই, এটি সুযোগ থেকে দূরে যেতে আরও কিছুটা সময় নিতে পারে তবে এর সাথে মোকাবিলা করার জন্য কেবলমাত্র একটি ঝুঁকির উল্লেখ রয়েছে।


3
রেফারেন্সটি 'ফর'-লুপের মধ্যে ঘোষণা করা হলেও প্রতিটি বস্তুর জন্য একটি নতুন রেফারেন্স বরাদ্দ করা হয় না। উভয় ক্ষেত্রে: ১) 'ও' একটি স্থানীয় পরিবর্তনশীল এবং ফাংশনের শুরুতে স্ট্যাকের জন্য একবার এটি বরাদ্দ করা হয়। 2) প্রতিটি পুনরাবৃত্তিতে একটি নতুন অবজেক্ট তৈরি করা হয়। সুতরাং পারফরম্যান্সে কোনও পার্থক্য নেই। কোড সংগঠন, পাঠযোগ্যতা এবং রক্ষণাবেক্ষণের জন্য, লুপের মধ্যে রেফারেন্স ঘোষণা করা ভাল dec
অজয় ভাটিয়া

1
যদিও আমি জাভার পক্ষে কথা বলতে পারছি না, .NET এ প্রথম উদাহরণে প্রতিটি বস্তুর জন্য রেফারেন্সটি 'বরাদ্দ' করা হয় না। স্থানীয় (পদ্ধতিতে) ভেরিয়েবলের জন্য স্ট্যাকের একক প্রবেশ রয়েছে। আপনার উদাহরণগুলির জন্য, তৈরি করা আইএলটি অভিন্ন।
জেসি সি স্লিকার

3

আমি মনে করি এটি সংকলকের উপর নির্ভর করে এবং একটি সাধারণ উত্তর দেওয়া শক্ত।


3

আমার অনুশীলন অনুসরণ করা হয়:

  • যদি ভেরিয়েবলের প্রকারটি সহজ হয় (int, ডাবল, ...) আমি ভেরিয়েন্ট বি পছন্দ করি (ভিতরে)।
    কারণ: ভেরিয়েবলের সুযোগ হ্রাস করা।

  • যদি পরিবর্তনশীল ধরণ সহজ নয় (কিছু classবা struct) আমি বৈকল্পিক পছন্দ করা একটি (বাইরে)।
    কারণ: কর্টর-ডটর কলগুলির সংখ্যা হ্রাস করা।


1

পারফরম্যান্সের দৃষ্টিকোণ থেকে, বাইরে (অনেক বেশি) ভাল।

public static void outside() {
    double intermediateResult;
    for(int i=0; i < Integer.MAX_VALUE; i++){
        intermediateResult = i;
    }
}

public static void inside() {
    for(int i=0; i < Integer.MAX_VALUE; i++){
        double intermediateResult = i;
    }
}

আমি উভয় ফাংশন প্রতিটি 1 বিলিয়ন বার চালিত। এর বাইরে () 65 মিলিসেকেন্ড নিয়েছিল। ভিতরে () 1.5 সেকেন্ড সময় নিয়েছে।


2
নিশ্চয়ই তখন ডিবাগ অপ্রচলিত সংকলন হয়েছে, তাই না?
টমাসজ প্রিজিচোডজকি

(; j <0x3e8; j ++) এর জন্য int j = 0 এভাবে একবারে উভয় পরিবর্তনশীল হিসাবে ঘোষিত, এবং প্রতিটি চক্রের জন্য নয়। 2) অ্যাসাইনমেন্টটি এটি অন্যান্য বিকল্পের চেয়ে বেশি চর্বিযুক্ত। 3) সুতরাং সেরা অনুশীলনের নিয়ম হল এর জন্য পুনরাবৃত্তির বাইরে কোনও ঘোষণা।
লুকা

1

নোড ৪.০.০ সহ আমি জেএসের জন্য পরীক্ষা করেছিলাম যদি কারও আগ্রহ থাকে। লুপের বাইরে ঘোষণা করার ফলে প্রতি পরীক্ষায় 100 মিলিয়ন লুপ পুনরাবৃত্তি সহ 1000 টিরও বেশি ট্রায়ালে গড়ে ~ .5 এমএসের পারফরম্যান্সের উন্নতি ঘটে। সুতরাং আমি বলতে চাই যে এগিয়ে যাও এবং এটি সবচেয়ে পাঠযোগ্য / রক্ষণাবেক্ষণযোগ্য পদ্ধতিতে লিখুন যা বি, ইমো। আমি আমার কোডটি একটি বেহালার মধ্যে রাখব, তবে আমি এখন নোড মডিউলটির পারফরম্যান্সটি ব্যবহার করেছি। কোডটি এখানে:

var now = require("../node_modules/performance-now")

// declare vars inside loop
function varInside(){
    for(var i = 0; i < 100000000; i++){
        var temp = i;
        var temp2 = i + 1;
        var temp3 = i + 2;
    }
}

// declare vars outside loop
function varOutside(){
    var temp;
    var temp2;
    var temp3;
    for(var i = 0; i < 100000000; i++){
        temp = i
        temp2 = i + 1
        temp3 = i + 2
    }
}

// for computing average execution times
var insideAvg = 0;
var outsideAvg = 0;

// run varInside a million times and average execution times
for(var i = 0; i < 1000; i++){
    var start = now()
    varInside()
    var end = now()
    insideAvg = (insideAvg + (end-start)) / 2
}

// run varOutside a million times and average execution times
for(var i = 0; i < 1000; i++){
    var start = now()
    varOutside()
    var end = now()
    outsideAvg = (outsideAvg + (end-start)) / 2
}

console.log('declared inside loop', insideAvg)
console.log('declared outside loop', outsideAvg)

0

ক) খ এর চেয়ে নিরাপদ বাজি) ......... ভেবে দেখুন আপনি যদি 'ইনট' বা 'ভাসা' না দিয়ে লুপে কাঠামো শুরু করছেন তবে কি?

মত

typedef struct loop_example{

JXTZ hi; // where JXTZ could be another type...say closed source lib 
         // you include in Makefile

}loop_example_struct;

//then....

int j = 0; // declare here or face c99 error if in loop - depends on compiler setting

for ( ;j++; )
{
   loop_example loop_object; // guess the result in memory heap?
}

আপনি অবশ্যই মেমরি ফাঁস নিয়ে সমস্যায় পড়তে বাধ্য! সুতরাং আমি বিশ্বাস করি যে 'এ' নিরাপদ বাজি এবং 'বি' নিবিড় উত্স লাইব্রেরিগুলিতে কাজ করার জন্য মেমরি জমে থাকা ঝুঁকিপূর্ণ You আপনি লিনাক্সের 'ভালগ্রাইন্ড' সরঞ্জামটি বিশেষত উপ সরঞ্জাম 'হেলগ্রাইন্ড' ব্যবহার করতে পারেন।


0

এটি একটি আকর্ষণীয় প্রশ্ন। আমার অভিজ্ঞতা থেকে বিবেচনা করার জন্য একটি চূড়ান্ত প্রশ্ন রয়েছে যখন আপনি কোনও কোডের জন্য এই বিষয়ে বিতর্ক করবেন:

ভেরিয়েবলটি বিশ্বব্যাপী হওয়ার কোনও কারণ আছে কি?

এটি স্থানীয়ভাবে বহুবার বিপরীত হিসাবে বিশ্বব্যাপী একবার কেবল পরিবর্তনশীল ঘোষণা করার জন্য অর্থবোধ করে কারণ এটি কোডটি সংগঠিত করার পক্ষে ভাল এবং কোডের কম লাইনের প্রয়োজন হয় requires যাইহোক, যদি এটি কেবলমাত্র একটি পদ্ধতির মধ্যে স্থানীয়ভাবে ঘোষণা করার প্রয়োজন হয় তবে আমি সেটিকে এ পদ্ধতিতে আরম্ভ করব যাতে এটি স্পষ্ট হয় যে ভেরিয়েবলটি কেবল সেই পদ্ধতির সাথে প্রাসঙ্গিক। আপনি যদি পরবর্তী বিকল্পটি বেছে নেন তবে এই পদ্ধতিটি যেভাবে শুরু করা হয়েছে তার বাইরে এই ভেরিয়েবলটিকে কল না করার বিষয়ে সতর্ক থাকুন - আপনার কোডটি আপনি কী সম্পর্কে কথা বলছেন তা জানতে পারবেন না এবং একটি ত্রুটির প্রতিবেদন করবে।

এছাড়াও, পার্শ্ব নোট হিসাবে, স্থানীয় উদ্দেশ্যগুলি বিভিন্ন পদ্ধতির মধ্যে নকল করবেন না যদিও তাদের উদ্দেশ্যগুলি অদৃশ্য রয়েছে; এটা ঠিক বিভ্রান্ত হয়।


1
লল আমি অনেক কারণে একমত নই ... তবে কোনও ভোট নেই ... আমি আপনার নির্বাচনের অধিকারকে সম্মান করি
গ্র্যান্টলি

0

এটি আরও ভাল ফর্ম

double intermediateResult;
int i = byte.MinValue;

for(; i < 1000; i++)
{
intermediateResult = i;
System.out.println(intermediateResult);
}

1) এভাবে একবারে উভয় পরিবর্তনশীল হিসাবে ঘোষিত হয়, এবং প্রতিটি চক্রের জন্য নয়। 2) অ্যাসাইনমেন্টটি এটি অন্যান্য বিকল্পের চেয়ে বেশি চর্বিযুক্ত। 3) সুতরাং সেরা অনুশীলনের নিয়ম হল এর জন্য পুনরাবৃত্তির বাইরে কোনও ঘোষণা।


0

go tool compile -Sগোতে একই জিনিস চেষ্টা করে দেখুন এবং Go 1.9.4 এর সাথে ব্যবহার করে সংকলক আউটপুট তুলনা করুন

জিরো পার্থক্য, এসেম্বলারের আউটপুট অনুযায়ী।


0

দীর্ঘদিন ধরে আমার এই একই প্রশ্ন ছিল। সুতরাং আমি একটি এমনকি সহজ টুকরা কোড পরীক্ষা।

উপসংহার: জন্য এই ক্ষেত্রে আছে কোন কর্মক্ষমতা পার্থক্য।

বাইরে লুপ কেস

int intermediateResult;
for(int i=0; i < 1000; i++){
    intermediateResult = i+2;
    System.out.println(intermediateResult);
}

ভিতরে লুপ কেস

for(int i=0; i < 1000; i++){
    int intermediateResult = i+2;
    System.out.println(intermediateResult);
}

আমি ইন্টেলিজের ডিকম্পিলারটিতে সংকলিত ফাইলটি পরীক্ষা করেছিলাম এবং উভয় ক্ষেত্রেই আমি একই পেয়েছি Test.class

for(int i = 0; i < 1000; ++i) {
    int intermediateResult = i + 2;
    System.out.println(intermediateResult);
}

আমি এই উত্তরে প্রদত্ত পদ্ধতিটি ব্যবহার করে উভয়ের ক্ষেত্রে কোড বিযুক্ত করেছি । আমি উত্তরের সাথে কেবল প্রাসঙ্গিক অংশগুলি দেখাব

বাইরে লুপ কেস

Code:
  stack=2, locals=3, args_size=1
     0: iconst_0
     1: istore_2
     2: iload_2
     3: sipush        1000
     6: if_icmpge     26
     9: iload_2
    10: iconst_2
    11: iadd
    12: istore_1
    13: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
    16: iload_1
    17: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
    20: iinc          2, 1
    23: goto          2
    26: return
LocalVariableTable:
        Start  Length  Slot  Name   Signature
           13      13     1 intermediateResult   I
            2      24     2     i   I
            0      27     0  args   [Ljava/lang/String;

ভিতরে লুপ কেস

Code:
      stack=2, locals=3, args_size=1
         0: iconst_0
         1: istore_1
         2: iload_1
         3: sipush        1000
         6: if_icmpge     26
         9: iload_1
        10: iconst_2
        11: iadd
        12: istore_2
        13: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        16: iload_2
        17: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
        20: iinc          1, 1
        23: goto          2
        26: return
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
           13       7     2 intermediateResult   I
            2      24     1     i   I
            0      27     0  args   [Ljava/lang/String;

আপনি যদি মনোযোগ দিয়ে মনোযোগ দেন, কেবলমাত্র Slotনিযুক্ত করা iএবং intermediateResultইন LocalVariableTableতাদের উপস্থিতি ক্রমের একটি পণ্য হিসাবে অদলবদল করা হবে। স্লটে একই পার্থক্য কোডের অন্যান্য লাইনে প্রতিফলিত হয়।

  • কোনও অতিরিক্ত অপারেশন করা হচ্ছে না
  • intermediateResult উভয় ক্ষেত্রে এখনও স্থানীয় পরিবর্তনশীল, তাই কোনও পার্থক্য অ্যাক্সেসের সময় নেই।

বোনাস

সংকলকগণ এক টন অপ্টিমাইজেশন করেন, এই ক্ষেত্রে কী ঘটে তা একবার দেখুন।

জিরো কাজের ক্ষেত্রে

for(int i=0; i < 1000; i++){
    int intermediateResult = i;
    System.out.println(intermediateResult);
}

জিরোর কাজ পচে গেছে

for(int i = 0; i < 1000; ++i) {
    System.out.println(i);
}

-1

এমনকি যদি আমি জানি যে আমার সংকলকটি যথেষ্ট স্মার্ট, তবে আমি এটির উপর নির্ভর করতে পছন্দ করব না, এবং এ) রূপটি ব্যবহার করব।

খ) বৈকল্পিকটি কেবল তখনই আপনার কাছে বোধগম্য হয় যদি আপনার ইন্টারমিডিয়েটরিসাল্ট করার প্রয়োজন হয় লুপ বডি পরে রেজাল্ট অনুপলব্ধ । তবে আমি এরকম হতাশার পরিস্থিতি কল্পনা করতে পারি না, যাইহোক ...

সম্পাদনা: জোন স্কিটি একটি খুব ভাল পয়েন্ট তৈরি করেছে, এটি দেখায় যে একটি লুপের ভিতরে পরিবর্তনশীল ঘোষণাটি প্রকৃত অর্থগত পার্থক্য করতে পারে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.