কোনও রেঞ্জের লুপের মধ্যে মানচিত্র থেকে নির্বাচিত কীগুলি সরিয়ে ফেলা নিরাপদ?


135

কীভাবে একজন মানচিত্র থেকে নির্বাচিত কীগুলি সরিয়ে ফেলতে পারেন? delete()নীচের কোডের মতোই কি পরিসরের সাথে একত্রিত করা নিরাপদ ?

package main

import "fmt"

type Info struct {
    value string
}

func main() {
    table := make(map[string]*Info)

    for i := 0; i < 10; i++ {
        str := fmt.Sprintf("%v", i)
        table[str] = &Info{str}
    }

    for key, value := range table {
        fmt.Printf("deleting %v=>%v\n", key, value.value)
        delete(table, key)
    }
}

https://play.golang.org/p/u1vufvEjSw

উত্তর:


174

এটি নিরাপদ! আপনি কার্যকর গোতেও একই ধরণের সন্ধান করতে পারেন :

for key := range m {
    if key.expired() {
        delete(m, key)
    }
}

এবং ভাষা নির্দিষ্টকরণ :

মানচিত্রের উপর পুনরাবৃত্তি ক্রম নির্দিষ্ট করা হয়নি এবং এক পুনরাবৃত্তি থেকে পরের দিকে একইরূপে গ্যারান্টিযুক্ত নয়। যদি এখনও মানচিত্রের প্রবেশপত্রগুলি পৌঁছায়নি তবে পুনরাবৃত্তির সময় সরিয়ে ফেলা হয় তবে সংশ্লিষ্ট পুনরাবৃত্তির মানগুলি উত্পাদিত হবে না। যদি মানচিত্রের এন্ট্রিগুলি পুনরাবৃত্তির সময় তৈরি করা হয় তবে সেই প্রবেশটি পুনরাবৃত্তির সময় উত্পন্ন হতে পারে বা এড়িয়ে যেতে পারে। তৈরি প্রতিটি এন্ট্রি এবং এক পুনরাবৃত্তি থেকে পরের দিকে পৃথক হতে পারে। মানচিত্রটি শূন্য হলে পুনরাবৃত্তির সংখ্যা 0 হয়।


key.expired অপরিশোধিত (টাইপ স্ট্রিংয়ের কোনও ক্ষেত্র বা পদ্ধতিটির মেয়াদ শেষ নেই)

4
@ ক্রিস্টেন - উপরে বর্ণিত উদাহরণে, কীটি স্ট্রিং নয় বরং func (a T) expired() boolইন্টারফেস প্রয়োগ করে এমন কিছু কাস্টম টাইপ হওয়া উচিত । এই উদাহরণের উদ্দেশ্যে, আপনি চেষ্টা করতে পারেন: m := make(map[int]int) /* populate m here somehow */ for key := range (m) { if key % 2 == 0 { /* this is just some condition, such as calling expired */ delete(m, key); } }
19:40

খুবই বিভ্রান্তিকর.
g10guang

150

সেবাস্তিয়ানের উত্তরটি সঠিক, তবে কেন এটি নিরাপদ তা আমি জানতে চেয়েছিলাম , তাই আমি মানচিত্রের উত্স কোডটিতে কিছু খনন করেছি । এটি কল করার মতো মনে হচ্ছে delete(k, v), এটি মূলত কেবল মূল্য মুছার পরিবর্তে একটি পতাকা সেট করে (পাশাপাশি গণনা মান পরিবর্তন করে):

b->tophash[i] = Empty;

(খালি মূল্য একটি ধ্রুবক 0)

মানচিত্রটি যা করছে বলে মনে হচ্ছে তা মানচিত্রের আকারের উপর নির্ভর করে একটি সেট সংখ্যক বালতি বরাদ্দ করা হচ্ছে, যা আপনি 2^B( এই উত্স কোড থেকে ) হারে সন্নিবেশ সম্পাদন করার সাথে সাথে বাড়বে :

byte    *buckets;     // array of 2^B Buckets. may be nil if count==0.

সুতরাং আপনার ব্যবহারের চেয়ে প্রায় সবসময় বেশি বালতি বরাদ্দ রয়েছে এবং আপনি যখন rangeমানচিত্রের উপরে একটি কাজ করেন, এটি tophashপ্রতিটি বালতিটির সেই মানটি পরীক্ষা করে এটি পরীক্ষা করতে 2^Bপারে কিনা তা পরীক্ষা করে।

সংক্ষিপ্তসার হিসাবে, একটি এর deleteঅভ্যন্তরীণটি rangeনিরাপদ কারণ তথ্য প্রযুক্তিগতভাবে এখনও রয়েছে, তবে এটি যখন পরীক্ষা করে তখন tophashএটি দেখতে পাবে যে এটি কেবল এটি এড়িয়ে যেতে পারে এবং rangeআপনি যে কোনও ক্রিয়াকলাপ সম্পাদন করছেন তা এতে অন্তর্ভুক্ত করতে পারে না । উত্স কোড এমনকি একটি অন্তর্ভুক্ত TODO:

 // TODO: consolidate buckets if they are mostly empty
 // can only consolidate if there are no live iterators at this size.

এটি ব্যাখ্যা করে যে delete(k,v)ফাংশনটি ব্যবহার করা আসলে মেমরিটি মুক্ত করে না, কেবল আপনাকে যে বালতিতে অ্যাক্সেসের অনুমতি দেওয়া হয়েছে তার তালিকা থেকে সরিয়ে দেয়। আপনি যদি সত্যিকারের স্মৃতি মুক্ত করতে চান তবে আপনাকে পুরো মানচিত্রটি অ্যাক্সেসযোগ্য করে তুলতে হবে যাতে আবর্জনা সংগ্রহের পদক্ষেপটি শুরু হয়। আপনি একটি লাইনের সাহায্যে এটি করতে পারেন

map = nil

2
সুতরাং মনে হচ্ছে আপনি মানচিত্রে যে কোনও স্বেচ্ছাসেবক মান মুছে ফেলা নিরাপদ বলছেন, কেবলমাত্র 'বর্তমান' এক নয়, সঠিক? এবং যখন আমি আগে ইচ্ছামত মুছে ফেলা একটি হ্যাশ মূল্যায়ন করার সময় আসে তখন এটি নিরাপদে এড়িয়ে যাবে?
ঝাঁকুনি

আপনি এটি এই খেলার মাঠ play.golang.org/p/FwbsghzrsO থেকে দেখতে পারেন যে এটি সঠিক, @ ফ্লিমজি । মনে রাখবেন যে সূচকগুলি আপনি মুছে ফেলেন সেটি যদি প্রথমে থাকে তবে এটি ইতিমধ্যে কে, ভিতে লিখিত হওয়ার পরেও এটি দেখায় তবে আপনি যদি সূচকটি প্রথমটির বাইরে কোনওটিকে সেট করেন তবে এটি কেবল দুটি কী প্রদর্শন করবে / তিনটির পরিবর্তে মান জোড়া এবং আতঙ্কিত নয় ic
ভেরান

1
"প্রকৃতপক্ষে স্মৃতি মুক্ত করে না" কি এখনও প্রাসঙ্গিক? উত্সটিতে মন্তব্য করার চেষ্টা করেছি কিন্তু এটি খুঁজে পাচ্ছি না।
টনি

11
গুরুত্বপূর্ণ দ্রষ্টব্য: মনে রাখবেন যে এটি কেবলমাত্র বর্তমান বাস্তবায়ন , এবং এটি ভবিষ্যতে পরিবর্তিত হতে পারে, সুতরাং আপনাকে "সমর্থন" হিসাবে প্রদর্শিত হতে পারে এমন কোনও অতিরিক্ত বৈশিষ্ট্যের উপর নির্ভর করতে হবে না। আপনার কেবলমাত্র গ্যারান্টি হ'ল সেবাস্তিয়ানদের উত্তরে বর্ণিত স্পেসিফিকেশন দ্বারা সরবরাহ করা । (তাই বলা হয়, অন্বেষণ এবং যান অভ্যন্তরীণ ব্যাখ্যা কি না নিশ্চিত আকর্ষণীয়, educating এবং সাধারণত সন্ত্রস্ত!)
akavel

4

আমি ভাবছিলাম কোনও স্মৃতি ফাঁস হতে পারে কিনা। সুতরাং আমি একটি পরীক্ষা প্রোগ্রাম লিখেছি:

package main

import (
    log "github.com/Sirupsen/logrus"
    "os/signal"
    "os"
    "math/rand"
    "time"
)

func main() {
    log.Info("=== START ===")
    defer func() { log.Info("=== DONE ===") }()

    go func() {
        m := make(map[string]string)
        for {
            k := GenerateRandStr(1024)
            m[k] = GenerateRandStr(1024*1024)

            for k2, _ := range m {
                delete(m, k2)
                break
            }
        }
    }()

    osSignals := make(chan os.Signal, 1)
    signal.Notify(osSignals, os.Interrupt)
    for {
        select {
        case <-osSignals:
            log.Info("Recieved ^C command. Exit")
            return
        }
    }
}

func GenerateRandStr(n int) string {
    rand.Seed(time.Now().UnixNano())
    const letterBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    b := make([]byte, n)
    for i := range b {
        b[i] = letterBytes[rand.Int63() % int64(len(letterBytes))]
    }
    return string(b)
}

দেখে মনে হচ্ছে জিসি डो স্মৃতি মুক্ত করে es সুতরাং এটি ঠিক আছে।


0

সংক্ষেপে, হ্যাঁ পূর্ববর্তী উত্তরগুলি দেখুন।

এবং এটিও এখান থেকে :

ianlancetaylor ফেব্রুয়ারী 18, 2015 এ মন্তব্য করেছে
আমি মনে করি এটি বোঝার মূল চাবিকাঠিটি বুঝতে হবে যে একটি / রেঞ্জ স্টেটমেন্টের বডি কার্যকর করার সময় কোনও বর্তমান পুনরাবৃত্তি নেই। এমন মানগুলির একটি সেট রয়েছে যা দেখা গেছে, এবং মানগুলির একটি সেট যা দেখা যায় নি। দেহটি সম্পাদন করার সময়, দেখা গেছে এমন একটি কী / মান জুটি - সর্বাধিক সাম্প্রতিক জুটি - পরিসর বিবৃতিটির পরিবর্তনশীলকে দেওয়া হয়েছিল to এই কী / মান জুটি সম্পর্কে বিশেষ কিছু নেই, এটি পুনরুক্তির সময় ইতিমধ্যে দেখা গেছে এমন একটির মধ্যে।

তিনি যে প্রশ্নের উত্তর দিচ্ছেন তা হ'ল কোনও rangeঅপারেশনের সময় মানচিত্রের উপাদানগুলিকে সংশোধন করার বিষয়ে , যে কারণে তিনি "বর্তমান পুনরাবৃত্তি" উল্লেখ করেছেন। তবে এটি এখানেও প্রাসঙ্গিক: আপনি একটি ব্যাপ্তির সময় কীগুলি মুছতে পারেন, এবং এর অর্থ হ'ল আপনি পরে এগুলি পরিসরে দেখতে পাবেন না (এবং যদি আপনি ইতিমধ্যে সেগুলি দেখে থাকেন তবে ঠিক আছে)।

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