কীভাবে দক্ষতার সাথে স্ট্রিংগুলি দক্ষতার সাথে যুক্ত করতে হয়


727

গো- stringতে একটি আদিম প্রকার, যার অর্থ এটি কেবল পঠনযোগ্য এবং এর প্রত্যেকটি হেরফের একটি নতুন স্ট্রিং তৈরি করবে।

সুতরাং যদি আমি ফলাফলটির স্ট্রিংয়ের দৈর্ঘ্য না জেনে অনেক বার স্ট্রিংগুলি সংহত করতে চাই, তবে এটি করার সর্বোত্তম উপায় কী?

নিষ্পাপ উপায় হবে:

s := ""
for i := 0; i < 1000; i++ {
    s += getShortStringFromSomewhere()
}
return s

তবে এটি খুব কার্যকর বলে মনে হচ্ছে না।



1
দ্রষ্টব্য: এই প্রশ্ন এবং বেশিরভাগ উত্তরগুলি ভাষায় আসার আগে লেখা হয়েছিল বলে মনে হয়, এটি এটির append()জন্য একটি ভাল সমাধান। এটি দ্রুত পারফরম্যান্স করবে copy()তবে প্রথমে স্লাইসটি বাড়বে এমনকি এর অর্থ যদি সক্ষমতা পর্যাপ্ত না হয় তবে একটি নতুন ব্যাকিং অ্যারে বরাদ্দ করা। bytes.Bufferআপনি যদি এর অতিরিক্ত সুবিধার পদ্ধতিগুলি চান বা আপনি যে প্যাকেজটি ব্যবহার করছেন এটি যদি তা প্রত্যাশা করে তবে এখনও তা বোধগম্য হয়।
থোমাসর্টটার

7
এটি কেবল "খুব অদক্ষ বলে মনে হয় না"; এটিতে একটি নির্দিষ্ট সমস্যা রয়েছে যে প্রতি নতুন নন-সিএস ভাড়া আমরা প্রথম সপ্তাহে কাজ শুরু করেছি। এটি চতুর্ভুজ - ও (এন * এন)। সংখ্যা ক্রম সম্বন্ধে চিন্তা করুন: 1 + 2 + 3 + 4 + ...। এটি n*(n+1)/2, বেসের ত্রিভুজের ক্ষেত্রফল n। আপনি যখন লুপে অপরিবর্তনীয় স্ট্রিং যুক্ত করেন তখন আপনি আকার 1, তারপরে আকার 2, তারপর আকার 3 ইত্যাদি বরাদ্দ করেন। এই চতুষ্কোণ সংস্থান খরচ কেবল এটির চেয়ে আরও বেশি উপায়ে নিজেকে প্রকাশ করে।
রব

উত্তর:


856

নতুন উপায়:

Go 1.10 থেকে একটি strings.Builderধরণ রয়েছে, আরও বিশদের জন্য দয়া করে এই উত্তরটি একবার দেখুন

পুরানো উপায়:

bytesপ্যাকেজটি ব্যবহার করুন । এটি একটি Bufferপ্রকার যা প্রয়োগ করে io.Writer

package main

import (
    "bytes"
    "fmt"
)

func main() {
    var buffer bytes.Buffer

    for i := 0; i < 1000; i++ {
        buffer.WriteString("a")
    }

    fmt.Println(buffer.String())
}

এটি ও (এন) সময়ে এটি করে।


24
মুদ্রণের পরিবর্তে (স্ট্রিং (বাফার.বাইটস ())); ব্যবহার কেবল প্রিন্টলন করতে পারে (বাফার.স্ট্রিং ())
চিত্র

26
পরিবর্তে buffer := bytes.NewBufferString(""), আপনি করতে পারেন var buffer bytes.Buffer। আপনার সেই সেমিকোলনগুলির কোনও দরকার নেই :)।
পাগল 2be

66
অবিশ্বাস্যভাবে দ্রুত। আমার প্রোগ্রামটিতে কিছু নিষ্পাপ "+" স্ট্রিং কনক্যাট তৈরি করেছেন 3 মিনিট থেকে 1.3 সেকেন্ডে
ম্যালকম

10
"ও (এন) সময়" এর জন্য +1; আমি মনে করি এটির মতো আরও মন্তব্য করা জরুরী।
contradictioned

8
যান 1.10 যোগ strings.Builder , যা bytes.Buffer মত হল কিন্তু দ্রুত আপনার শেষ লক্ষ্য একটি স্ট্রিং হয়।
জোশ ব্লিচার স্নাইডার

272

স্ট্রিংগুলি সংঘবদ্ধ করার সবচেয়ে কার্যকরী উপায় হ'ল বিল্টিন ফাংশনটি copy। আমার পরীক্ষায়, এই পদ্ধতির ব্যবহারের চেয়ে ~ 3x দ্রুত bytes.Bufferএবং অপারেটরটি ব্যবহার করার চেয়ে অনেক বেশি দ্রুত (,000 12,000x) +। এছাড়াও, এটি কম স্মৃতি ব্যবহার করে।

আমি এটি প্রমাণ করার জন্য একটি পরীক্ষার কেস তৈরি করেছি এবং ফলাফল এখানে:

BenchmarkConcat  1000000    64497 ns/op   502018 B/op   0 allocs/op
BenchmarkBuffer  100000000  15.5  ns/op   2 B/op        0 allocs/op
BenchmarkCopy    500000000  5.39  ns/op   0 B/op        0 allocs/op

নীচে পরীক্ষার জন্য কোড দেওয়া হল:

package main

import (
    "bytes"
    "strings"
    "testing"
)

func BenchmarkConcat(b *testing.B) {
    var str string
    for n := 0; n < b.N; n++ {
        str += "x"
    }
    b.StopTimer()

    if s := strings.Repeat("x", b.N); str != s {
        b.Errorf("unexpected result; got=%s, want=%s", str, s)
    }
}

func BenchmarkBuffer(b *testing.B) {
    var buffer bytes.Buffer
    for n := 0; n < b.N; n++ {
        buffer.WriteString("x")
    }
    b.StopTimer()

    if s := strings.Repeat("x", b.N); buffer.String() != s {
        b.Errorf("unexpected result; got=%s, want=%s", buffer.String(), s)
    }
}

func BenchmarkCopy(b *testing.B) {
    bs := make([]byte, b.N)
    bl := 0

    b.ResetTimer()
    for n := 0; n < b.N; n++ {
        bl += copy(bs[bl:], "x")
    }
    b.StopTimer()

    if s := strings.Repeat("x", b.N); string(bs) != s {
        b.Errorf("unexpected result; got=%s, want=%s", string(bs), s)
    }
}

// Go 1.10
func BenchmarkStringBuilder(b *testing.B) {
    var strBuilder strings.Builder

    b.ResetTimer()
    for n := 0; n < b.N; n++ {
        strBuilder.WriteString("x")
    }
    b.StopTimer()

    if s := strings.Repeat("x", b.N); strBuilder.String() != s {
        b.Errorf("unexpected result; got=%s, want=%s", strBuilder.String(), s)
    }
}

6
বাইটস.বাফারটি মূলত অনুলিপিটির মতোই করা উচিত (আমার ধারণা অনুসারে কিছু অতিরিক্ত বুককিপিং সহ) এবং গতিটি আলাদা নয়। সুতরাং আমি যে ব্যবহার করব :)। পার্থক্যটি হচ্ছে যে বাফারটি 0 বাইট দিয়ে শুরু হয় তাই এটি পুনর্বিবেচনা করতে হবে (এটি এটি অনুমান করে আমাকে একটু ধীর বলে মনে হয়)। যদিও ব্যবহার করা সহজ।
আকতাউ

5
buffer.Write(বাইটস) এর চেয়ে 30% বেশি দ্রুত buffer.WriteString। [আপনি যদি ডেটা পেতে পারেন তবে দরকারী []byte]
দানি-বিআর

34
নোট করুন যে মাপদণ্ডের ফলাফলগুলি বিকৃত এবং প্রামাণিক নয়। বিভিন্ন মানদণ্ডের সাথে বিভিন্ন মানদণ্ডের জন্য ডাকা হবে b.Nএবং সুতরাং আপনি একই কাজটি সম্পাদনের সময়টির সাথে তুলনা করছেন না (উদাহরণস্বরূপ একটি ফাংশন 1,000স্ট্রিংগুলিকে সংযোজন করতে পারে, অন্য কোনওটি সংযোজন করতে পারে 10,000যা গড়ে বড় পার্থক্য তৈরি করতে পারে BenchmarkConcat()উদাহরণস্বরূপ 1 টি সংযোজনের সময় । আপনি প্রতিটি ক্ষেত্রে (অবশ্যই না একই পরিশেষে যোগ গণনা ব্যবহার করা উচিত b.N), এবং শরীরের ভিতরে সব সংযুক্তকরণের না forপর্যন্ত b.N(যে, 2 forলুপ এমবেডেড)।
আইজজা 8

18
অতিরিক্তভাবে, অনুলিপিটি গ্রহণের সময়টিকে স্পষ্টভাবে উপেক্ষা করে অনুলিপি করা হয়, যা অন্যান্য বেঞ্চমার্কগুলিতে অন্তর্ভুক্ত থাকে।
gha.st

6
অতিরিক্তভাবে, কপির বেঞ্চমার্ক ফলাফলের স্ট্রিংয়ের দৈর্ঘ্য জানার উপর নির্ভর করে।
স্কারলোট 20

227

যান 1.10+ রয়েছে strings.Builder, এখানে

একটি বিল্ডার দক্ষতার সাথে লেখার পদ্ধতিগুলি ব্যবহার করে স্ট্রিং তৈরি করতে ব্যবহৃত হয়। এটি মেমরির অনুলিপিটি হ্রাস করে। শূন্য মানটি ব্যবহারের জন্য প্রস্তুত।


উদাহরণ

এটা প্রায় একই bytes.Buffer

package main

import (
    "strings"
    "fmt"
)

func main() {
    // ZERO-VALUE:
    //
    // It's ready to use from the get-go.
    // You don't need to initialize it.
    var str strings.Builder

    for i := 0; i < 1000; i++ {
        str.WriteString("a")
    }

    fmt.Println(str.String())
}

খেলার মাঠে এটি দেখতে ক্লিক করুন


বিঃদ্রঃ

  • স্ট্রিংবিল্ডার মানটি অনুলিপি করবেন না কারণ এটি অন্তর্নিহিত ডেটা ক্যাশে করে।
  • আপনি যদি একটি স্ট্রিংবিল্ডার মান ভাগ করতে চান তবে এটিতে একটি পয়েন্টার ব্যবহার করুন।

সমর্থিত ইন্টারফেস

স্ট্রিংবিল্ডারের পদ্ধতিগুলি বিদ্যমান ইন্টারফেসগুলি মাথায় রেখে প্রয়োগ করা হচ্ছে। যাতে আপনি আপনার কোডটিতে সহজেই নতুন বিল্ডার টাইপটিতে স্যুইচ করতে পারেন।


বাইটস থেকে পৃথক

  • এটি কেবল বৃদ্ধি বা পুনরায় সেট করতে পারে।

  • এটির একটি অন্তর্নির্মিত একটি অনুলিপি-চেক প্রক্রিয়া রয়েছে যা এটি অনুলিপি করে অনুলিপি করে:

    func (b *Builder) copyCheck() { ... }

  • ইন bytes.Buffer, এক ভালো অন্তর্নিহিত বাইট অ্যাক্সেস করতে পারে: (*Buffer).Bytes()

    • strings.Builder এই সমস্যা রোধ করে
    • কখনও কখনও, এটি সমস্যা এবং পরিবর্তে পছন্দসই নয়।
    • উদাহরণস্বরূপ: উঁকি দেওয়া আচরণের জন্য যখন বাইটগুলি কোনও io.Readerইত্যাদিতে পাস করা হয়

আরও তথ্যের জন্য এর উত্স কোডটি এখানে দেখুন


5
'পালাতে' বলতে কী বোঝ? আপনি কী বোঝাতে চেয়েছেন যে স্ট্রিংয়ে পালিয়ে গেছে, বা কেবল যে অন্তর্নিহিত বাইটগুলি প্রকাশ করা যেতে পারে?
মাখদুমী

1
@ মাখদুমি হ্যাঁ, দ্বিতীয়, অন্তর্নিহিত বাইটগুলির এক্সপোজার।
ইনঙ্ক গুমাস

মূল্য লক্ষ্য strings.Builderকরা একটি পয়েন্টার রিসিভার ব্যবহার করে এর পদ্ধতিগুলি প্রয়োগ করে, যা আমাকে এক মুহুর্তের জন্য ফেলে দিয়েছিল। ফলস্বরূপ, আমি সম্ভবত এটি ব্যবহার করে তৈরি করব new
ডানকান জোন্স

@ ডানকোনজোনস আমি একটি নোট যুক্ত করেছি, যদিও এটি বেশিরভাগ ক্ষেত্রে ডেটা ক্যাচিংয়ের জন্য ব্যবহৃত হয়, ফানকস জুড়ে ভাগ করে নেওয়ার সময় এটিতে পয়েন্টার ব্যবহার করা স্বাভাবিক etc. একই ফানકમાં আপনি এটি একটি পয়েন্টার হিসাবেও ব্যবহার করতে পারেন।
Inanc Gumus

130

স্ট্রিং প্যাকেজে একটি লাইব্রেরির ফাংশন রয়েছে Join: http://golang.org/pkg/strings/# জোইন

কোডের এক Joinনজরে অ্যাপিড ফাংশনের অনুরূপ দৃষ্টিভঙ্গি দেখানো হয়েছে কিনপিকো লিখেছেন: https://golang.org/src/strings/strings.go#L420

ব্যবহার:

import (
    "fmt";
    "strings";
)

func main() {
    s := []string{"this", "is", "a", "joined", "string\n"};
    fmt.Printf(strings.Join(s, " "));
}

$ ./test.bin
this is a joined string

21
যখন আপনাকে এমন কোনও জিনিস লুপ করতে হয় যা কোনও [] স্ট্রিং নয় তখন কাজ করে না।
ম্যালকম

42

আমি স্রেফ উপরে আমার নিজস্ব কোডে পোস্ট করা শীর্ষ জবাবকে বেঞ্চমার্ক করেছি (একটি পুনরাবৃত্ত গাছের পদচারণা) এবং সাধারণ কনক্যাট অপারেটরটি আসলে এর চেয়ে দ্রুততর BufferString

func (r *record) String() string {
    buffer := bytes.NewBufferString("");
    fmt.Fprint(buffer,"(",r.name,"[")
    for i := 0; i < len(r.subs); i++ {
        fmt.Fprint(buffer,"\t",r.subs[i])
    }
    fmt.Fprint(buffer,"]",r.size,")\n")
    return buffer.String()
}

এটি 0.81 সেকেন্ড সময় নিয়েছে, যেখানে নিম্নলিখিত কোডটি রয়েছে:

func (r *record) String() string {
    s := "(\"" + r.name + "\" ["
    for i := 0; i < len(r.subs); i++ {
        s += r.subs[i].String()
    }
    s += "] " + strconv.FormatInt(r.size,10) + ")\n"
    return s
} 

মাত্র 0.61 সেকেন্ড সময় নিয়েছে। এটি সম্ভবত নতুন তৈরির ওভারহেডের কারণে BufferString

আপডেট: আমিও joinফাংশনটি বেঞ্চমার্ক করেছি এবং এটি 0.54 সেকেন্ডে চলেছে।

func (r *record) String() string {
    var parts []string
    parts = append(parts, "(\"", r.name, "\" [" )
    for i := 0; i < len(r.subs); i++ {
        parts = append(parts, r.subs[i].String())
    }
    parts = append(parts, strconv.FormatInt(r.size,10), ")\n")
    return strings.Join(parts,"")
}

5
আমি বিশ্বাস করি যে ওপি রানটাইম জটিলতার চেয়ে মেমরির জটিলতায় বেশি চিন্তিত ছিল, নিরপেক্ষ স্ট্রিং কনটেন্টেশনগুলির ফলে প্রতিবার নতুন মেমরি বরাদ্দ পাওয়া যায় memory
galaktor

15
এর ধীর গতির পরিবর্তে fmt.Fprint ব্যবহারের সাথে সম্পর্কিত হতে পারেbuffer.WriteString("\t"); buffer.WriteString(subs[i]);
রবার্ট জ্যাক উইল

আমি জেনে খুশি যে আমার পছন্দের পদ্ধতিটি (strings.Join)দ্রুততম হিসাবে চালানো হয়েছে যখন এই উক্তিটি যে (bytes.Buffer)বিজয়ী!
চিতাবাহন

23

আপনি বাইটের একটি বড় স্লাইস তৈরি করতে এবং স্ট্রিং স্লাইস ব্যবহার করে এতে ছোট স্ট্রিংয়ের বাইটগুলি অনুলিপি করতে পারেন। "কার্যকর গো" তে একটি ফাংশন দেওয়া আছে:

func Append(slice, data[]byte) []byte {
    l := len(slice);
    if l + len(data) > cap(slice) { // reallocate
        // Allocate double what's needed, for future growth.
        newSlice := make([]byte, (l+len(data))*2);
        // Copy data (could use bytes.Copy()).
        for i, c := range slice {
            newSlice[i] = c
        }
        slice = newSlice;
    }
    slice = slice[0:l+len(data)];
    for i, c := range data {
        slice[l+i] = c
    }
    return slice;
}

তারপরে অপারেশনগুলি শেষ হয়ে গেলে, string ( )এটি আবার স্ট্রিংয়ে রূপান্তর করতে বাইটের বড় টুকরো ব্যবহার করুন।


এটি আকর্ষণীয় যে গোতে এটি করার অনেকগুলি উপায় রয়েছে।
যিটজাক

11
কার্যকর যেতে যেতে, এটি আরও বলে যে ধারণাটি এত কার্যকর যে এটি একটি বিল্টিনে বন্দী হয়েছিল। সুতরাং আপনি আপনার ফাংশনটি এর সাথে প্রতিস্থাপন করতে পারেন append(slice, byte...)বলে মনে হয়।
আকতাউ

23

এটি দ্রুততম সমাধান যা আপনাকে সামগ্রিক বাফার আকারটি আগে জানতে বা গণনা করার প্রয়োজন হয় না:

var data []byte
for i := 0; i < 1000; i++ {
    data = append(data, getShortStringFromSomewhere()...)
}
return string(data)

আমার বেঞ্চমার্ক অনুসারে , এটি অনুলিপি সমাধানের তুলনায় 20% ধীর (6.72ns এর পরিবর্তে 8.1ns) তবে বাইটস.বাফার ব্যবহারের চেয়ে 55% দ্রুত।


23
package main

import (
  "fmt"
)

func main() {
    var str1 = "string1"
    var str2 = "string2"
    out := fmt.Sprintf("%s %s ",str1, str2)
    fmt.Println(out)
}

2
স্ট্যাক ওভারফ্লোতে স্বাগতম! সহায়তা কেন্দ্রে সম্পাদনা সহায়তাটি পড়তে কিছুক্ষণ সময় নিন । স্ট্যাক ওভারফ্লোতে ফর্ম্যাট করা অন্যান্য সাইটের চেয়ে আলাদা।
Rizier123

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

সহজ সমাধান 👍
ফিন

22

নোট 2018 এ যুক্ত হয়েছে

Go 1.10 থেকে একটি strings.Builderধরণ রয়েছে, আরও বিশদের জন্য দয়া করে এই উত্তরটি একবার দেখুন

প্রাক -201x উত্তর

@ সিডি 1 এর বেঞ্চমার্ক কোড এবং অন্যান্য উত্তরগুলি ভুল। b.Nবেঞ্চমার্ক ফাংশনে সেট করার কথা নয়। এটি পরীক্ষার কার্য সম্পাদনের সময়টি স্থিতিশীল কিনা তা নির্ধারণ করতে গ-টেস্ট সরঞ্জাম দ্বারা গতিশীলভাবে সেট করা হয়েছে।

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

package main

import (
    "bytes"
    "strings"
    "testing"
)

const (
    sss = "xfoasneobfasieongasbg"
    cnt = 10000
)

var (
    bbb      = []byte(sss)
    expected = strings.Repeat(sss, cnt)
)

func BenchmarkCopyPreAllocate(b *testing.B) {
    var result string
    for n := 0; n < b.N; n++ {
        bs := make([]byte, cnt*len(sss))
        bl := 0
        for i := 0; i < cnt; i++ {
            bl += copy(bs[bl:], sss)
        }
        result = string(bs)
    }
    b.StopTimer()
    if result != expected {
        b.Errorf("unexpected result; got=%s, want=%s", string(result), expected)
    }
}

func BenchmarkAppendPreAllocate(b *testing.B) {
    var result string
    for n := 0; n < b.N; n++ {
        data := make([]byte, 0, cnt*len(sss))
        for i := 0; i < cnt; i++ {
            data = append(data, sss...)
        }
        result = string(data)
    }
    b.StopTimer()
    if result != expected {
        b.Errorf("unexpected result; got=%s, want=%s", string(result), expected)
    }
}

func BenchmarkBufferPreAllocate(b *testing.B) {
    var result string
    for n := 0; n < b.N; n++ {
        buf := bytes.NewBuffer(make([]byte, 0, cnt*len(sss)))
        for i := 0; i < cnt; i++ {
            buf.WriteString(sss)
        }
        result = buf.String()
    }
    b.StopTimer()
    if result != expected {
        b.Errorf("unexpected result; got=%s, want=%s", string(result), expected)
    }
}

func BenchmarkCopy(b *testing.B) {
    var result string
    for n := 0; n < b.N; n++ {
        data := make([]byte, 0, 64) // same size as bootstrap array of bytes.Buffer
        for i := 0; i < cnt; i++ {
            off := len(data)
            if off+len(sss) > cap(data) {
                temp := make([]byte, 2*cap(data)+len(sss))
                copy(temp, data)
                data = temp
            }
            data = data[0 : off+len(sss)]
            copy(data[off:], sss)
        }
        result = string(data)
    }
    b.StopTimer()
    if result != expected {
        b.Errorf("unexpected result; got=%s, want=%s", string(result), expected)
    }
}

func BenchmarkAppend(b *testing.B) {
    var result string
    for n := 0; n < b.N; n++ {
        data := make([]byte, 0, 64)
        for i := 0; i < cnt; i++ {
            data = append(data, sss...)
        }
        result = string(data)
    }
    b.StopTimer()
    if result != expected {
        b.Errorf("unexpected result; got=%s, want=%s", string(result), expected)
    }
}

func BenchmarkBufferWrite(b *testing.B) {
    var result string
    for n := 0; n < b.N; n++ {
        var buf bytes.Buffer
        for i := 0; i < cnt; i++ {
            buf.Write(bbb)
        }
        result = buf.String()
    }
    b.StopTimer()
    if result != expected {
        b.Errorf("unexpected result; got=%s, want=%s", string(result), expected)
    }
}

func BenchmarkBufferWriteString(b *testing.B) {
    var result string
    for n := 0; n < b.N; n++ {
        var buf bytes.Buffer
        for i := 0; i < cnt; i++ {
            buf.WriteString(sss)
        }
        result = buf.String()
    }
    b.StopTimer()
    if result != expected {
        b.Errorf("unexpected result; got=%s, want=%s", string(result), expected)
    }
}

func BenchmarkConcat(b *testing.B) {
    var result string
    for n := 0; n < b.N; n++ {
        var str string
        for i := 0; i < cnt; i++ {
            str += sss
        }
        result = str
    }
    b.StopTimer()
    if result != expected {
        b.Errorf("unexpected result; got=%s, want=%s", string(result), expected)
    }
}

পরিবেশ ওএস এক্স 10.11.6, 2.2 গিগাহার্টজ ইন্টেল কোর আই 7

পরীক্ষার ফলাফল:

BenchmarkCopyPreAllocate-8         20000             84208 ns/op          425984 B/op          2 allocs/op
BenchmarkAppendPreAllocate-8       10000            102859 ns/op          425984 B/op          2 allocs/op
BenchmarkBufferPreAllocate-8       10000            166407 ns/op          426096 B/op          3 allocs/op
BenchmarkCopy-8                    10000            160923 ns/op          933152 B/op         13 allocs/op
BenchmarkAppend-8                  10000            175508 ns/op         1332096 B/op         24 allocs/op
BenchmarkBufferWrite-8             10000            239886 ns/op          933266 B/op         14 allocs/op
BenchmarkBufferWriteString-8       10000            236432 ns/op          933266 B/op         14 allocs/op
BenchmarkConcat-8                     10         105603419 ns/op        1086685168 B/op    10000 allocs/op

উপসংহার:

  1. CopyPreAllocateদ্রুততম উপায়; AppendPreAllocateনং 1 এর খুব কাছে, তবে কোডটি লেখা সহজ।
  2. Concatগতি এবং মেমরির ব্যবহারের জন্য উভয়ই সত্যিই খারাপ পারফরম্যান্স করেছে। এটি ব্যবহার করবেন না।
  3. Buffer#WriteBuffer#WriteString@ দানি-বি মন্তব্যে যা বলেছেন তার বিপরীতে এবং মূলত গতিতে একইরকম। বিবেচনা stringকরা সত্যিই []byteগো-তে রয়েছে, এটি বোধগম্য।
  4. বাইটস.বাফার মূলত Copyঅতিরিক্ত বই রাখার এবং অন্যান্য স্টাফের মতো একই সমাধানটি ব্যবহার করে ।
  5. Copyএবং Append64৪ এর বুটস্ট্র্যাপ আকারটি ব্যবহার করুন, এটি বাইটস-বুফারের সমান
  6. Appendআরও মেমরি এবং বরাদ্দ ব্যবহার করুন, আমি মনে করি এটি এর ব্যবহারের বৃদ্ধি অ্যালগরিদমের সাথে সম্পর্কিত। এটি বাইটস হিসাবে দ্রুত স্মৃতি বাড়ছে না B বাফার

প্রস্তাবনা:

  1. সাধারণ কাজের জন্য যেমন ওপি যা চায়, আমি তা ব্যবহার করব Appendবা করব AppendPreAllocate। এটি যথেষ্ট দ্রুত এবং সহজেই ব্যবহারযোগ্য।
  2. যদি একই সাথে বাফারটি পড়তে এবং লেখার প্রয়োজন হয় তবে bytes.Bufferঅবশ্যই ব্যবহার করুন । এটি এর জন্য ডিজাইন করা হয়েছে।

13

আমার মূল পরামর্শ ছিল

s12 := fmt.Sprint(s1,s2)

তবে উপরে বাইটস ব্যবহার করে উত্তর। বাফার - রাইটিংস্ট্রিং () সবচেয়ে কার্যকর উপায়।

আমার প্রাথমিক পরামর্শটি প্রতিবিম্ব এবং একটি টাইপ সুইচ ব্যবহার করে। মৌলিক ধরণের জন্য দেখুন (p *pp) doPrintএবং(p *pp) printArg
কোনও সার্বজনীন স্ট্রিংজার () ইন্টারফেস নেই, যেমনটি আমি ভদ্রভাবে ভাবছিলাম।

কমপক্ষে যদিও, স্প্রিন্ট () অভ্যন্তরীণভাবে একটি বাইটস.বাফার ব্যবহার করে। এইভাবে

`s12 := fmt.Sprint(s1,s2,s3,s4,...,s1000)`

মেমরি বরাদ্দের ক্ষেত্রে গ্রহণযোগ্য।

=> স্প্রিন্ট () সংক্ষেপণ দ্রুত ডিবাগ আউটপুট জন্য ব্যবহার করা যেতে পারে।
=> অন্যথায় বাইটস ব্যবহার করুন uff বাফার ... রাইটিংস্ট্রিং


8
এটি অন্তর্নির্মিত নয় এবং এটি দক্ষও নয়।
পিটারএসও

প্যাকেজ আমদানি করা (যেমন fmt) এর অর্থ এটি অন্তর্নির্মিত নয়। এটি স্ট্যান্ডার্ড লাইব্রেরিতে রয়েছে।
ম্যালকম

এটি কেবল ধীর কারণ এটি তার যুক্তিগুলির প্রতিচ্ছবি ব্যবহার করে। এটা কার্যকর। অন্যথায় এটি
স্ট্রিংয়ের

11

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

go test -bench=. -benchtime=100ms

আমার থিঙ্কপ্যাড টি 400 এ ফল দেয়:

BenchmarkAppendEmpty    50000000         5.0 ns/op
BenchmarkAppendPrealloc 50000000         3.5 ns/op
BenchmarkCopy           20000000        10.2 ns/op

4

এটি @ সিডি 1 ( Go 1.8, linux x86_64) দ্বারা সরবরাহ করা বেঞ্চমার্কের আসল সংস্করণ যা @ আইকজা এবং @ পিকবয়ের দ্বারা উল্লিখিত বাগগুলির ফিক্সগুলি সহ।

Bytes.Bufferঅপারেটরের 7মাধ্যমে ডাইরেক্ট স্ট্রিং কনটেনটেশনের চেয়ে মাত্র কয়েকগুণ দ্রুত +

package performance_test

import (
    "bytes"
    "fmt"
    "testing"
)

const (
    concatSteps = 100
)

func BenchmarkConcat(b *testing.B) {
    for n := 0; n < b.N; n++ {
        var str string
        for i := 0; i < concatSteps; i++ {
            str += "x"
        }
    }
}

func BenchmarkBuffer(b *testing.B) {
    for n := 0; n < b.N; n++ {
        var buffer bytes.Buffer
        for i := 0; i < concatSteps; i++ {
            buffer.WriteString("x")
        }
    }
}

সময়:

BenchmarkConcat-4                             300000          6869 ns/op
BenchmarkBuffer-4                            1000000          1186 ns/op

আমি মনে করি না যে ম্যানুয়ালি বিএন সেট করা টেস্টিং প্যাকেজের বেঞ্চমার্ক ফাংশনগুলি ব্যবহার করার সঠিক উপায়
পিকবয়

@ পিকবয়, আপনার দৃষ্টিভঙ্গিটি ন্যায়সঙ্গত করুন। আপনি কেন b.Nপাবলিক পরিবর্তনশীল বলে মনে করেন ?
ভিটালি ইসাইভ

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

@ পিকবয়, আপনি যদি পরীক্ষার সরঞ্জামটিকে b.Nগতিশীল সেট করতে দেন তবে আপনি বিভিন্ন পরীক্ষার ক্ষেত্রে বিভিন্ন দৈর্ঘ্যের একটি স্ট্রিং দিয়ে শেষ করে দেবেন। মন্তব্য
ভিটালি evশায়েভ

এজন্য আপনার বিএন লুপের মধ্যে 10000 এর মতো নির্দিষ্ট সংখ্যার পুনরাবৃত্তির একটি অভ্যন্তরীণ লুপ যুক্ত করা উচিত।
পিকবয়

3

goutils.JoinBetween

 func JoinBetween(in []string, separator string, startIndex, endIndex int) string {
    if in == nil {
        return ""
    }

    noOfItems := endIndex - startIndex

    if noOfItems <= 0 {
        return EMPTY
    }

    var builder strings.Builder

    for i := startIndex; i < endIndex; i++ {
        if i > startIndex {
            builder.WriteString(separator)
        }
        builder.WriteString(in[i])
    }
    return builder.String()
}

1

আমি নিম্নলিখিতটি ব্যবহার করে এটি করি: -

package main

import (
    "fmt"
    "strings"
)

func main (){
    concatenation:= strings.Join([]string{"a","b","c"},"") //where second parameter is a separator. 
    fmt.Println(concatenation) //abc
}

এটি ওপি-র লুপের সাহায্যে ধারাবাহিক পুনরাবৃত্তির মাধ্যমে একটি স্ট্রিং তৈরির সমস্যার সমাধান করে না।
কোডফোরস্টার

1
package main

import (
"fmt"
)

func main() {
    var str1 = "string1"
    var str2 = "string2"
    result := make([]byte, 0)
    result = append(result, []byte(str1)...)
    result = append(result, []byte(str2)...)
    result = append(result, []byte(str1)...)
    result = append(result, []byte(str2)...)

    fmt.Println(string(result))
}

3
দয়া করে কেবল উত্তরগুলি পোস্ট করবেন না। এই কোডটি কী করে এবং কেন এটি সমাধান তা দয়া করে একটি ব্যাখ্যা দিন।
কোরাশেন

-1

মেমরি বরাদ্দ পরিসংখ্যান সহ মানদণ্ডের ফলাফল। গিথুবে বেঞ্চমার্ক কোডটি পরীক্ষা করুন ।

পারফরম্যান্স অনুকূল করতে স্ট্রিং.বিল্ডার ব্যবহার করুন।

go test -bench . -benchmem
goos: darwin
goarch: amd64
pkg: github.com/hechen0/goexp/exps
BenchmarkConcat-8                1000000             60213 ns/op          503992 B/op          1 allocs/op
BenchmarkBuffer-8               100000000               11.3 ns/op             2 B/op          0 allocs/op
BenchmarkCopy-8                 300000000                4.76 ns/op            0 B/op          0 allocs/op
BenchmarkStringBuilder-8        1000000000               4.14 ns/op            6 B/op          0 allocs/op
PASS
ok      github.com/hechen0/goexp/exps   70.071s

আপনি এখানে তৈরি করছেন এমন মূল পরীক্ষার জন্য দয়া করে @ সিডি 1 কে ক্রেডিট দিন।
colm.anseo

-2
s := fmt.Sprintf("%s%s", []byte(s1), []byte(s2))

5
এটি সমাধান খুব ধীর, কারণ এটি প্রতিবিম্ব ব্যবহার করে, এটি ফর্ম্যাট স্ট্রিংকে পার্স করে এবং []byte(s1)রূপান্তরটির জন্য এটি ডেটার একটি অনুলিপি তৈরি করে । পোস্ট করা অন্যান্য সমাধানগুলির সাথে এটির তুলনা করা, আপনি কি নিজের সমাধানের একক সুবিধার নাম বলতে পারবেন?
pts

-5

strings.Join() "স্ট্রিং" প্যাকেজ থেকে

আপনার যদি কোনও টাইপ মিল না থাকে (যেমন আপনি যদি কোনও ইন্টার এবং স্ট্রিংয়ে যোগ দেওয়ার চেষ্টা করছেন), আপনি র‌্যান্ডমটাইপ করুন (জিনিসটি যা আপনি পরিবর্তন করতে চান)

গো EX:

package main

import (
    "fmt"
    "strings"
)

var intEX = 0
var stringEX = "hello all you "
var stringEX2 = "people in here"


func main() {
    s := []string{stringEX, stringEX2}
    fmt.Println(strings.Join(s, ""))
}

আউটপুট:

hello all you people in here

4
এই কোডটিও সংকলন করে না: strings.Join()মাত্র 2 টি প্যারামিটার লাগে: একটি টুকরো এবং বিভাজক string
আইকজা

এটি সাহায্য করতে পারে না
আনশু

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