.NET এ দুটি বাইট অ্যারের তুলনা করা


541

আমি কীভাবে এই দ্রুত করতে পারি?

অবশ্যই আমি এটি করতে পারি:

static bool ByteArrayCompare(byte[] a1, byte[] a2)
{
    if (a1.Length != a2.Length)
        return false;

    for (int i=0; i<a1.Length; i++)
        if (a1[i]!=a2[i])
            return false;

    return true;
}

তবে আমি এটির জন্য কোনও বিসিএল ফাংশন বা কিছু উচ্চতর অনুকূলিত প্রমাণিত উপায় খুঁজছি ।

java.util.Arrays.equals((sbyte[])(Array)a1, (sbyte[])(Array)a2);

দুর্দান্তভাবে কাজ করে তবে এটি x64 এর মতো কাজ করবে বলে মনে হচ্ছে না।

আমার অতি দ্রুত উত্তরটি এখানে নোট করুন


1
"এই ধরণের বিষয়টি গণ্য হয়েছে যে অ্যারেগুলি কীওয়ার্ড প্রান্তিককরণ শুরু করে।" যদি এটি একটি বড়। এটি প্রতিবিম্বিত করার জন্য আপনার কোডটি ঠিক করা উচিত।
জো চুং

4
ফিরুন
অ্যালারি

আমি @OhadSchneider উত্তর পছন্দ করেছেIStructuralEquatable
LCJ

উত্তর:


613

আপনি Enumerable.SequenceEqual পদ্ধতিটি ব্যবহার করতে পারেন ।

using System;
using System.Linq;
...
var a1 = new int[] { 1, 2, 3};
var a2 = new int[] { 1, 2, 3};
var a3 = new int[] { 1, 2, 4};
var x = a1.SequenceEqual(a2); // true
var y = a1.SequenceEqual(a3); // false

যদি আপনি কোনও কারণে .NET 3.5 ব্যবহার করতে না পারেন তবে আপনার পদ্ধতিটি ঠিক আছে।
সংকলক-রান-টাইম পরিবেশটি আপনার লুপটিকে অনুকূল করে তুলবে যাতে আপনাকে পারফরম্যান্স সম্পর্কে চিন্তা করার দরকার নেই।


4
তবে সিকোয়েন্সএকুয়াল কোনও অনিরাপদ তুলনার চেয়ে প্রক্রিয়া করতে বেশি সময় নেয় না? বিশেষত যখন আপনার তুলনা করা হচ্ছে 1000?
tcables

90
হ্যাঁ, এটি অনিরাপদ তুলনার তুলনায় প্রায় 50x ধীর গতিতে চলে।
হাফথর

27
এটি সত্যই এখানে মৃতদের উত্থাপন করছে, তবে ধীরে ধীরে এখানে ব্যবহারের জন্য খারাপ শব্দ। 50x ধীর গতিতে খারাপ শোনাচ্ছে , তবে এটির পরিবর্তনের জন্য আপনি যথেষ্ট পরিমাণে ডেটা তুলনা করেন না এবং যদি আপনি হন তবে অগণিত কারণে আপনার নিজের ক্ষেত্রে এটি সত্যই বেনমার্ক করা দরকার। উদাহরণস্বরূপ, 50x ধীর গতির বিপরীতে অনিরাপদ উত্তরের স্রষ্টাকে 7x ধীরের পার্থক্যের বিষয়টি নোট করুন (অনিরাপদ পদ্ধতির গতিটিও ডেটা সাজানোর উপর নির্ভর করে) depends বিরল ক্ষেত্রে যেখানে এই সংখ্যাগুলি গুরুত্বপূর্ণ, পি / ইনভোক আরও দ্রুত।
সিলালী অ্যাডোবর

4
সুতরাং ধীর প্রয়োগটি 300 টির বেশি পছন্দ পেয়েছে? আমি MSvcrt.dll হুক করার পরামর্শ দিচ্ছি কারণ এটি কাজটি সর্বাধিক দ্রুত করা হবে।
টিগারেট

69
দ্রুততম ব্যবসায়ের পক্ষে সবচেয়ে গুরুত্বপূর্ণ বিষয় নয়। এই কোডের সঞ্চয়ীকরণের তুলনায় রক্ষণাবেক্ষণের পরিমাণ অনেক বেশি "দ্রুত" ক্ষেত্রে 99% ক্ষেত্রে সমান হবে। আমি সিকোয়েন্সএকুয়াল ব্যবহার করছি এবং আমার সম্পূর্ণ কোডটি <1 এমএস। আপনি যেগুলি সংরক্ষণ করছেন সেগুলি পি / ইনভোকের পাঠযোগ্যতার অভাবের 5 মিনিটের মধ্যে কখনই যোগ করবে না।
PRMan

236

পি / চালান ক্ষমতা সক্রিয়!

[DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]
static extern int memcmp(byte[] b1, byte[] b2, long count);

static bool ByteArrayCompare(byte[] b1, byte[] b2)
{
    // Validate buffers are the same length.
    // This also ensures that the count does not exceed the length of either buffer.  
    return b1.Length == b2.Length && memcmp(b1, b2, b1.Length) == 0;
}

48
পি / ইনভোক ইয়া - এটি বিটম্যাপে কমপক্ষে দ্রুততম হিসাবে প্রমাণিত হয়েছে: stackoverflow.com/questions/2031217/…
এরিক ফোর্বস

25
এই ক্ষেত্রে পিনিং প্রয়োজনীয় নয় necessary পিনভোকের সাথে নেটিভ কোডটি কল করার সময় মার্শালার স্বয়ংক্রিয় পিনিং সম্পাদন করে। তথ্যসূত্র: স্ট্যাকওভারফ্লো.com
মার্ক গ্লাসগো

14
পি / ইনভোকে বুসগুলি প্রকাশ করতে পারে তবে আমি অনিরাপদ পয়েন্টার-আকারের তুলনা ব্যবহার করে এমন একটি বাস্তবায়ন সহ উপস্থাপিত সমস্ত সমাধানের চেয়ে দ্রুততম সমাধান। রেফারেন্স সাম্যতা সহ নেটিভ কোডে কল করার আগে এবং প্রথম এবং শেষ উপাদানগুলির তুলনা করার আগে আপনি কয়েকটি অপ্টিমাইজেশন তৈরি করতে পারেন।
জোশ

38
বউ কেন? পোস্টার একটি দ্রুত বাস্তবায়ন চেয়েছিল এবং একটি অনুকূলিত সংসদীয় ভাষার তুলনা বীট করা যায় না। P / INVOKE ছাড়াই NET এর বাইরে কীভাবে "REPE CMPSD" পাবেন তা আমি জানি না।
জেসন গোয়ামাত

14
নিতপিক: MSVCR.dll ব্যবহারকারীর কোড দ্বারা ব্যবহার করার কথা নয়। এমএসভিসিআর ব্যবহার করতে, আপনার বিতরণ করা সংস্করণটি রানটাইম বিতরণ করতে হবে। ( এমএসডিএন.মাইক্রোসফট.এইন / ইউএস / লিবারিয়ান/… এবং ব্লগস.এমএসডিএন / বি / সোલ્ડনিউথিং / আরচিভি / ২০১৪/০৪/
মিচ

160

নেট 4 - এর জন্য একটি নতুন অন্তর্নির্মিত সমাধান রয়েছে - IStructuralEquatable

static bool ByteArrayCompare(byte[] a1, byte[] a2) 
{
    return StructuralComparisons.StructuralEqualityComparer.Equals(a1, a2);
}

17
মতে এই ব্লগ পোস্টে আসলে খুব ধীর যে।
ম্যাট জনসন-পিন্ট

48
ক্রেজি আস্তে। লুপের জন্য সহজ থেকে প্রায় 180x ধীর।
হাফথর

এটি কাজ করে, তবে কেন বুঝতে পারছি না। একটি বাইট [] একটি আদিম প্রকার যা IStructuralEquatable বাস্তবায়ন করে না, সুতরাং আপনি কেন এটি নিক্ষেপ করতে পারেন - এবং এটিতে একটি অন্তর্ভুক্ত কাস্ট! এবং তারপরে ইন্টারফেস "সমান" পদ্ধতিটি যাদুকরীভাবে উপলভ্য হয়ে যায় ... সেই পদ্ধতির বাস্তবায়নটি কোথা থেকে আসছে? কেউ কি আমাকে ক্লু করতে পারে?
জোশ

1
শুধু না কেন StructuralComparisons.StructuralEqualityComparer.Equals(a1, a2)। কোন NullReferenceExceptionএখানে s।
ta.speot.is

1
@ ta.speot.is ধন্যবাদ, একটি লাইনারের সাথে তর্ক করতে পারে না! পূর্ববর্তী সমাধানটি আরও কার্যকর ছিল যেহেতু এটি castালাইটিকে IStructuralEquatable (একটি অ্যারে স্থিরভাবে IStructuralEquatable হিসাবে পরিচিত) এ সংরক্ষণ করা হয়েছিল, তবে প্রকৃতপক্ষে আপনার পরামর্শগুলি পদ্ধতিটি নাল আর্গুমেন্টগুলির পক্ষেও কার্যকর করে তোলে।
ওহাদ স্নাইডার

76

ব্যবহারকারী গিল অনিরাপদ কোডের পরামর্শ দিয়েছেন যা এই সমাধানটি তৈরি করেছে:

// Copyright (c) 2008-2013 Hafthor Stefansson
// Distributed under the MIT/X11 software license
// Ref: http://www.opensource.org/licenses/mit-license.php.
static unsafe bool UnsafeCompare(byte[] a1, byte[] a2) {
  if(a1==a2) return true;
  if(a1==null || a2==null || a1.Length!=a2.Length)
    return false;
  fixed (byte* p1=a1, p2=a2) {
    byte* x1=p1, x2=p2;
    int l = a1.Length;
    for (int i=0; i < l/8; i++, x1+=8, x2+=8)
      if (*((long*)x1) != *((long*)x2)) return false;
    if ((l & 4)!=0) { if (*((int*)x1)!=*((int*)x2)) return false; x1+=4; x2+=4; }
    if ((l & 2)!=0) { if (*((short*)x1)!=*((short*)x2)) return false; x1+=2; x2+=2; }
    if ((l & 1)!=0) if (*((byte*)x1) != *((byte*)x2)) return false;
    return true;
  }
}

যা যতটা সম্ভব অ্যারের জন্য 64-বিট ভিত্তিক তুলনা করে। অ্যারেগুলি কীওয়ার্ডটি প্রান্তিককরণ শুরু করার বিষয়টি বিবেচনা করে। কিওয়ার্ড সারিবদ্ধ না হলে এটি কাজ করবে, এটি যেমন দ্রুত ছিল তত দ্রুত নয়।

এটি সাধারণ forলুপের চেয়ে প্রায় সাতটি টাইমার দ্রুত সম্পাদন করে । জে # লাইব্রেরি ব্যবহার করে মূল forলুপের সমান পারফর্ম করা হয়েছে । .সিকোয়েন্সএকুয়াল প্রায় সাতগুণ ধীর গতিতে চলে; আমি মনে করি যেহেতু এটি IEnumerator.MoveNext ব্যবহার করছে। আমি কল্পনা করি যে লিনকুই-ভিত্তিক সমাধানগুলি কমপক্ষে ধীর এবং খারাপ।


3
সুন্দর সমাধান। তবে একটি (ছোট) ইঙ্গিত: রেফারেন্স এ 1 এবং এ 2 সমান হলে একটি তুলনা জিনিসগুলিকে গতি দিতে পারে যদি কেউ এ 1 এবং বি 1 এর জন্য একই অ্যারে দেয়।
মিমি মিমি মিমি

12
.NET 4 x64 রিলিজের নতুন পরীক্ষার ডেটা: IStructualEquatable.equals ~ 180x ধীর, SequenceEqual 15x ধীর, SHA1 হ্যাশ 11x ধীর, বিট কনভার্টার-একই, অনিরাপদ 7x দ্রুত, পিনভোক 11x দ্রুত compare খুব সুন্দর যে মেমক্যাম্পে পি / ইনভোকের চেয়ে অনিরাপদ কেবল সামান্য কিছুটা ধীর।
হাফথর

3
এই লিঙ্কটি কেন মেমোরি প্রান্তিককরণ সম্পর্কে গুরুত্বপূর্ণ বিশদ দেয় যে ibm.com/developerworks/library/pa-dalign - সুতরাং, সারিবদ্ধতা পরীক্ষা করা একটি অপ্টিমাইজেশন হতে পারে এবং যদি উভয় অ্যারে একই পরিমাণে প্রান্তিককরণ বন্ধ থাকে তবে উভয় না হওয়া পর্যন্ত বাইট তুলনা করুন একটি কিওয়ার্ড সীমানায়।
হাফথর

5
যখন এ 1 এবং এ 2 উভয়ই বাতিল হয়ে যায় তবে এটি কি মিথ্যা দেবে?
নওফাল

2
@ ক্রিশ্দিডিয়াাকোনস্কু আমি কেভিনড্রাইডারের উত্তরটি লুপাইফাই করেছি। আমার সম্ভবত যা করা উচিত তা হ'ল পরীক্ষার স্যুট তৈরি করা এবং আমার ফলাফলগুলি গিথুবে উপলভ্য করা এবং এটি আমার উত্তরের সাথে লিঙ্ক করা।
হাফথর

73

Span<T> আপনার নিজের অ্যাপ্লিকেশনটির কোড বেসে বিভ্রান্তিকর এবং / অথবা বহনযোগ্য-ফ্লাফ ফেলে না দিয়ে চূড়ান্ত প্রতিযোগিতামূলক বিকল্প সরবরাহ করে:

// byte[] is implicitly convertible to ReadOnlySpan<byte>
static bool ByteArrayCompare(ReadOnlySpan<byte> a1, ReadOnlySpan<byte> a2)
{
    return a1.SequenceEqual(a2);
}

.NET কোর 3.1.0 হিসাবে বাস্তবায়নের (সাহসের) এখানে পাওয়া যাবে

এই পদ্ধতিটি যুক্ত করার জন্য আমি @ এলিআরবেলের গিস্টটি সংশোধন করেছি SpansEqual, অন্যের মানদণ্ডে বেশিরভাগ কম আকর্ষণীয় অভিনেতা বাদ দিয়েছি , এটি বিভিন্ন অ্যারে মাপ, আউটপুট গ্রাফ দিয়ে চালাচ্ছি SpansEqualএবং বেসলাইন হিসাবে চিহ্নিত করব যাতে এটি বিভিন্ন পদ্ধতির সাথে কীভাবে তুলনা করে তা জানায় SpansEqual

"ত্রুটি" কলামটি সরাতে হালকাভাবে সম্পাদিত নীচের সংখ্যাগুলি ফলাফলগুলি থেকে।

|        Method |  ByteCount |               Mean |            StdDev | Ratio |
|-------------- |----------- |-------------------:|------------------:|------:|
|    SpansEqual |         15 |           3.562 ns |         0.0035 ns |  1.00 |
|  LongPointers |         15 |           4.611 ns |         0.0028 ns |  1.29 |
|      Unrolled |         15 |          18.035 ns |         0.0195 ns |  5.06 |
| PInvokeMemcmp |         15 |          11.210 ns |         0.0353 ns |  3.15 |
|               |            |                    |                   |       |
|    SpansEqual |       1026 |          20.048 ns |         0.0286 ns |  1.00 |
|  LongPointers |       1026 |          63.347 ns |         0.1062 ns |  3.16 |
|      Unrolled |       1026 |          39.175 ns |         0.0304 ns |  1.95 |
| PInvokeMemcmp |       1026 |          40.830 ns |         0.0350 ns |  2.04 |
|               |            |                    |                   |       |
|    SpansEqual |    1048585 |      44,070.526 ns |        35.3348 ns |  1.00 |
|  LongPointers |    1048585 |      59,973.407 ns |        80.4145 ns |  1.36 |
|      Unrolled |    1048585 |      55,032.945 ns |        24.4745 ns |  1.25 |
| PInvokeMemcmp |    1048585 |      55,593.719 ns |        22.4301 ns |  1.26 |
|               |            |                    |                   |       |
|    SpansEqual | 2147483591 | 253,648,180.000 ns | 1,112,524.3074 ns |  1.00 |
|  LongPointers | 2147483591 | 249,412,064.286 ns | 1,079,409.5670 ns |  0.98 |
|      Unrolled | 2147483591 | 246,329,091.667 ns |   852,021.7992 ns |  0.97 |
| PInvokeMemcmp | 2147483591 | 247,795,940.000 ns | 3,390,676.3644 ns |  0.98 |

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

আমার সিস্টেম তথ্য:

BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18362
Intel Core i7-6850K CPU 3.60GHz (Skylake), 1 CPU, 12 logical and 6 physical cores
.NET Core SDK=3.1.100
  [Host]     : .NET Core 3.1.0 (CoreCLR 4.700.19.56402, CoreFX 4.700.19.56404), X64 RyuJIT
  DefaultJob : .NET Core 3.1.0 (CoreCLR 4.700.19.56402, CoreFX 4.700.19.56404), X64 RyuJIT

আমি কখনই ভাবিনি যে আমি যে সমস্ত স্টাফগুলিতে স্প্যান <T> বা এর কাছাকাছি কিছু ব্যবহার করব। আপনাকে ধন্যবাদ আমি এখন আমার সহকর্মীদের কাছে এটি নিয়ে বড়াই করতে পারি।
জোবব

সিকোয়েন্সএকুয়াল বিশেষত একটি স্প্যান পদ্ধতি হিসাবে প্রয়োগ করা হয়? ভেবেছিলাম এটি কেবলমাত্র একটি পরিমাণে বর্ধনযোগ্য পদ্ধতি was
জাস্টাই

1
@ জাস্টাই হ্যাঁ, {ReadOnly,}Span<T>এর নিজস্ব সংস্করণ রয়েছে SequenceEqual(একই নামের সাথে এটি সম্পর্কিত চুক্তিটি একই IEnumerable<T>এক্সটেনশন পদ্ধতির মতো, এটি আরও দ্রুত)। নোট করুন যে প্রকারের উপর বিধিনিষেধের কারণে এক্সটেনশন পদ্ধতিগুলি {ReadOnly,}Span<T>ব্যবহার করতে পারবেন না । IEnumerable<T>ref struct
জো অ্যামেন্টা

1
সিস্টেমটিকে @ সেন্টিনেল.মেমরি প্যাকেজের "পোর্টেবল" / "ধীর" Span<T>বাস্তবায়ন রয়েছে এর netstandard1.1উপরে এবং তারপরে (সুতরাং এটি কোনটি এই ইন্টারেক্টিভ চার্টের সাথে খেলুন )। "দ্রুত" Span<T>এই মুহূর্তে, .NET কোর 2.1 শুধুমাত্র উপলব্ধ, কিন্তু নোট যে জন্য SequenceEqual<T>বিশেষভাবে সেখানে "দ্রুত" এবং "ধীর" / "পোর্টেবল" (যদিও মধ্যে খুব সামান্য পার্থক্য হওয়া উচিত netstandard2.0সামান্য উন্নতি লক্ষ্যমাত্রা দেখতে পাবেন, কারণ তারা ভেক্টরাইজড কোড পাথ রয়েছে)।
জো অ্যামেন্টা

1
ইনস্টল-প্যাকেজ সিস্টেম.মেমোরি
ক্রিস মোসচিনি

30

যদি আপনি এটি করার বিরোধী না হন তবে আপনি জে # এসেম্বলি "vjslib.dll" আমদানি করতে পারেন এবং এর অ্যারেস.ইকুয়ালগুলি (বাইট [], বাইট []) পদ্ধতি ব্যবহার করতে পারেন ...

কেউ আপনাকে হাসলে যদি আমাকে দোষ দেবেন না ...


সম্পাদনা: এটির সামান্য দামের জন্য আমি এর জন্য কোডটি বিচ্ছিন্ন করতে রিফ্লেক্টরটি ব্যবহার করেছিলাম এবং এটি দেখতে এটির মতো দেখাচ্ছে:

public static bool equals(sbyte[] a1, sbyte[] a2)
{
  if (a1 == a2)
  {
    return true;
  }
  if ((a1 != null) && (a2 != null))
  {
    if (a1.Length != a2.Length)
    {
      return false;
    }
    for (int i = 0; i < a1.Length; i++)
    {
      if (a1[i] != a2[i])
      {
        return false;
      }
    }
    return true;
  }
  return false;
}

25

.NET 3.5 এবং আরও নতুনরকম একটি নতুন পাবলিক টাইপ রয়েছে System.Data.Linq.Binaryযা এনপ্যাপুলেট করে byte[]। এটি প্রয়োগ করে IEquatable<Binary>যে (কার্যকরভাবে) দুটি বাইট অ্যারে তুলনা করে। মনে রাখবেন যে এর System.Data.Linq.Binaryথেকে অন্তর্নিহিত রূপান্তর অপারেটরও রয়েছে byte[]

এমএসডিএন ডকুমেন্টেশন: সিস্টেম.ডাটা.লিনক.বাইনারি

সমান পদ্ধতির প্রতিবিম্বক decompile:

private bool EqualsTo(Binary binary)
{
    if (this != binary)
    {
        if (binary == null)
        {
            return false;
        }
        if (this.bytes.Length != binary.bytes.Length)
        {
            return false;
        }
        if (this.hashCode != binary.hashCode)
        {
            return false;
        }
        int index = 0;
        int length = this.bytes.Length;
        while (index < length)
        {
            if (this.bytes[index] != binary.bytes[index])
            {
                return false;
            }
            index++;
        }
    }
    return true;
}

আকর্ষণীয় মোচড়টি হ'ল দুটি বাইনারি অবজেক্টের হ্যাশগুলি একই হলে তারা কেবল বাই-বাই-বাইট তুলনা লুপে এগিয়ে যায় proceed এটি যাইহোক, Binaryঅবজেক্টগুলির কনস্ট্রাক্টারে হ্যাশের কম্পিউটিংয়ের ব্যয়ে ( forলুপ :-) দিয়ে অ্যারেটি অনুসরণ করে ))

উপরের বাস্তবায়নটির অর্থ হল যে সবচেয়ে খারাপ ক্ষেত্রে আপনাকে অ্যারেগুলি তিনবার অতিক্রম করতে হতে পারে: প্রথমে অ্যারে 1 এর হ্যাশ গণনা করতে হবে, তারপরে অ্যারে 2 এর হ্যাশ গণনা করতে হবে এবং অবশেষে (কারণ এটি সবচেয়ে খারাপ ক্ষেত্রে, দৈর্ঘ্য এবং হ্যাশ সমান) অ্যারে 1 এ বাইটগুলি অ্যারে 2 এ বাইট সহ।

সামগ্রিকভাবে, যদিও System.Data.Linq.Binaryছাত্রলীগের মধ্যে অন্তর্নির্মিত, আমি মনে করি না এটি দুটি বাইট অ্যারে তুলনা করার সবচেয়ে দ্রুততম উপায়: - |


20

বাইট [] শূন্যে পূর্ণ কিনা তা পরীক্ষা করার বিষয়ে আমি একই ধরণের প্রশ্ন পোস্ট করেছি । (সিমডি কোডটি মারধর করা হয়েছিল তাই আমি এটি এই উত্তরটি থেকে সরিয়ে দিয়েছি)) এখানে আমার তুলনা থেকে দ্রুততম কোডটি দেওয়া হয়েছে:

static unsafe bool EqualBytesLongUnrolled (byte[] data1, byte[] data2)
{
    if (data1 == data2)
        return true;
    if (data1.Length != data2.Length)
        return false;

    fixed (byte* bytes1 = data1, bytes2 = data2) {
        int len = data1.Length;
        int rem = len % (sizeof(long) * 16);
        long* b1 = (long*)bytes1;
        long* b2 = (long*)bytes2;
        long* e1 = (long*)(bytes1 + len - rem);

        while (b1 < e1) {
            if (*(b1) != *(b2) || *(b1 + 1) != *(b2 + 1) || 
                *(b1 + 2) != *(b2 + 2) || *(b1 + 3) != *(b2 + 3) ||
                *(b1 + 4) != *(b2 + 4) || *(b1 + 5) != *(b2 + 5) || 
                *(b1 + 6) != *(b2 + 6) || *(b1 + 7) != *(b2 + 7) ||
                *(b1 + 8) != *(b2 + 8) || *(b1 + 9) != *(b2 + 9) || 
                *(b1 + 10) != *(b2 + 10) || *(b1 + 11) != *(b2 + 11) ||
                *(b1 + 12) != *(b2 + 12) || *(b1 + 13) != *(b2 + 13) || 
                *(b1 + 14) != *(b2 + 14) || *(b1 + 15) != *(b2 + 15))
                return false;
            b1 += 16;
            b2 += 16;
        }

        for (int i = 0; i < rem; i++)
            if (data1 [len - 1 - i] != data2 [len - 1 - i])
                return false;

        return true;
    }
}

দুটি 256MB বাইট অ্যারে পরিমাপ করা হয়েছে:

UnsafeCompare                           : 86,8784 ms
EqualBytesSimd                          : 71,5125 ms
EqualBytesSimdUnrolled                  : 73,1917 ms
EqualBytesLongUnrolled                  : 39,8623 ms

1
আমি নিশ্চিত. আমি পরীক্ষাও চালিয়েছি। এটি উত্তরের চেয়ে দ্রুত যা মেমপ্যাম্প অসুরক্ষিত কল ব্যবহার করে।
ujenator

1
অ্যাম্বারড্যাব্ল্যাক আপনি কি নিশ্চিত? আপনি ছোট অ্যারে দিয়ে পরীক্ষা করেছেন?
জার শারদান

@ আরেকবালস্কি আপনি কি নিশ্চিত যে এটি মেমক্যাম্পের চেয়ে দ্রুততর, অন্যথায় আমার পরীক্ষার শোয়ের কারণ?
জার শারদান

আমি এই এবং মেমক্যাম্পের মধ্যে কার্যত অভিন্ন পারফরম্যান্স পেয়েছি, সুতরাং সম্পূর্ণ পরিচালিত সমাধানের জন্য +1।
মাইক মেরিনোস্কি

10
 using System.Linq; //SequenceEqual

 byte[] ByteArray1 = null;
 byte[] ByteArray2 = null;

 ByteArray1 = MyFunct1();
 ByteArray2 = MyFunct2();

 if (ByteArray1.SequenceEqual<byte>(ByteArray2) == true)
 {
    MessageBox.Show("Match");
 }
 else
 {
   MessageBox.Show("Don't match");
 }

1
এটাই আমি ব্যবহার করছি। তবে এটি উমম ... এমন একটি ক্রমিক তুলনা বলে মনে হচ্ছে যা আপনি অন্যথায় একটি সাধারণ লুপ ব্যবহার করে করতেন, অতএব খুব দ্রুত নয়। এটি প্রতিবিম্বিত করতে এবং আসলে কী করছে তা দেখতে সুন্দর লাগবে। নামটি দিয়ে বিচার করা, এটি অভিনব কিছু নয়।
সের্গে আখোপভ

1
হ্যাঁ, তবে স্বীকৃত উত্তরে ইতিমধ্যে উল্লেখ করা হয়েছে। বিটিডব্লিউ, আপনি সেখানে প্রকারের নির্দিষ্টকরণ সরিয়ে ফেলতে পারেন।
নওফাল

10

আরও একটি যুক্ত করা যাক!

সম্প্রতি মাইক্রোসফ্ট একটি বিশেষ নুগেট প্যাকেজ, সিস্টেম.রুনটাইম.কম্পিলার সার্ভিসস.উনসেফ প্রকাশ করেছে । এটি বিশেষ কারণ এটি আইএল-এ লেখা রয়েছে এবং নিম্ন-স্তরের কার্যকারিতা সরাসরি সি # তে উপলব্ধ নয় provides

এর একটি পদ্ধতি, Unsafe.As<T>(object)যেকোনো সুরক্ষা চেক এড়িয়ে কোনও রেফারেন্স টাইপকে অন্য রেফারেন্স টাইপে কাস্টিং করতে দেয়। এটি সাধারণত খুব খারাপ ধারণা, তবে যদি উভয় ধরণের কাঠামোগত একই হয় তবে এটি কাজ করতে পারে। সুতরাং আমরা একটি কাস্ট করার জন্য এই ব্যবহার করতে পারেন byte[]একটি থেকে long[]:

bool CompareWithUnsafeLibrary(byte[] a1, byte[] a2)
{
    if (a1.Length != a2.Length) return false;

    var longSize = (int)Math.Floor(a1.Length / 8.0);
    var long1 = Unsafe.As<long[]>(a1);
    var long2 = Unsafe.As<long[]>(a2);

    for (var i = 0; i < longSize; i++)
    {
        if (long1[i] != long2[i]) return false;
    }

    for (var i = longSize * 8; i < a1.Length; i++)
    {
        if (a1[i] != a2[i]) return false;
    }

    return true;
}

মনে রাখবেন যে long1.Lengthএটি এখনও অ্যারের মেমরি কাঠামোর কোনও ক্ষেত্রে সংরক্ষিত থাকায় মূল অ্যারের দৈর্ঘ্যটি ফিরিয়ে আনবে।

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

BenchmarkDotNet=v0.10.3.0, OS=Microsoft Windows NT 6.2.9200.0
Processor=Intel(R) Core(TM) i7-4870HQ CPU 2.50GHz, ProcessorCount=8
Frequency=2435775 Hz, Resolution=410.5470 ns, Timer=TSC
  [Host]     : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1637.0
  DefaultJob : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1637.0

                 Method |          Mean |    StdDev |
----------------------- |-------------- |---------- |
          UnsafeLibrary |   125.8229 ns | 0.3588 ns |
          UnsafeCompare |    89.9036 ns | 0.8243 ns |
           JSharpEquals | 1,432.1717 ns | 1.3161 ns |
 EqualBytesLongUnrolled |    43.7863 ns | 0.8923 ns |
              NewMemCmp |    65.4108 ns | 0.2202 ns |
            ArraysEqual |   910.8372 ns | 2.6082 ns |
          PInvokeMemcmp |    52.7201 ns | 0.1105 ns |

আমি সমস্ত পরীক্ষার সাথে একটি টুকরোটি তৈরি করেছি ।


এটি অনিরাপদ কীওয়ার্ডটি ব্যবহার করে না, তবুও এটি
সিস্টেমটি

আমি NewMemCmpAVX-2 ব্যবহারের জন্য আমার উত্তর আপডেট করেছি
মিঃ অ্যান্ডারসন

8

আমি এমন একটি পদ্ধতি তৈরি করেছি যা আমার পিসিতে সামান্য বীট memcmp()(প্লিনথের উত্তর) এবং খুব নিচুভাবে বীট করে EqualBytesLongUnrolled()(আরেক বুলস্কির উত্তর)। মূলত, এটি 8 টির পরিবর্তে 4 টি লুপটিকে তালিকাভুক্ত করে।

30 মার্চ 2019 আপডেট করুন :

.NET কোর 3.0 থেকে শুরু করে, আমাদের সিমডি সমর্থন রয়েছে!

এই সমাধানটি আমার পিসিতে যথেষ্ট মার্জিনের দ্বারা দ্রুততম:

#if NETCOREAPP3_0
using System.Runtime.Intrinsics.X86;
#endif


public static unsafe bool Compare(byte[] arr0, byte[] arr1)
{
    if (arr0 == arr1)
    {
        return true;
    }
    if (arr0 == null || arr1 == null)
    {
        return false;
    }
    if (arr0.Length != arr1.Length)
    {
        return false;
    }
    if (arr0.Length == 0)
    {
        return true;
    }
    fixed (byte* b0 = arr0, b1 = arr1)
    {
#if NETCOREAPP3_0
        if (Avx2.IsSupported)
        {
            return Compare256(b0, b1, arr0.Length);
        }
        else if (Sse2.IsSupported)
        {
            return Compare128(b0, b1, arr0.Length);
        }
        else
#endif
        {
            return Compare64(b0, b1, arr0.Length);
        }
    }
}
#if NETCOREAPP3_0
public static unsafe bool Compare256(byte* b0, byte* b1, int length)
{
    byte* lastAddr = b0 + length;
    byte* lastAddrMinus128 = lastAddr - 128;
    const int mask = -1;
    while (b0 < lastAddrMinus128) // unroll the loop so that we are comparing 128 bytes at a time.
    {
        if (Avx2.MoveMask(Avx2.CompareEqual(Avx.LoadVector256(b0), Avx.LoadVector256(b1))) != mask)
        {
            return false;
        }
        if (Avx2.MoveMask(Avx2.CompareEqual(Avx.LoadVector256(b0 + 32), Avx.LoadVector256(b1 + 32))) != mask)
        {
            return false;
        }
        if (Avx2.MoveMask(Avx2.CompareEqual(Avx.LoadVector256(b0 + 64), Avx.LoadVector256(b1 + 64))) != mask)
        {
            return false;
        }
        if (Avx2.MoveMask(Avx2.CompareEqual(Avx.LoadVector256(b0 + 96), Avx.LoadVector256(b1 + 96))) != mask)
        {
            return false;
        }
        b0 += 128;
        b1 += 128;
    }
    while (b0 < lastAddr)
    {
        if (*b0 != *b1) return false;
        b0++;
        b1++;
    }
    return true;
}
public static unsafe bool Compare128(byte* b0, byte* b1, int length)
{
    byte* lastAddr = b0 + length;
    byte* lastAddrMinus64 = lastAddr - 64;
    const int mask = 0xFFFF;
    while (b0 < lastAddrMinus64) // unroll the loop so that we are comparing 64 bytes at a time.
    {
        if (Sse2.MoveMask(Sse2.CompareEqual(Sse2.LoadVector128(b0), Sse2.LoadVector128(b1))) != mask)
        {
            return false;
        }
        if (Sse2.MoveMask(Sse2.CompareEqual(Sse2.LoadVector128(b0 + 16), Sse2.LoadVector128(b1 + 16))) != mask)
        {
            return false;
        }
        if (Sse2.MoveMask(Sse2.CompareEqual(Sse2.LoadVector128(b0 + 32), Sse2.LoadVector128(b1 + 32))) != mask)
        {
            return false;
        }
        if (Sse2.MoveMask(Sse2.CompareEqual(Sse2.LoadVector128(b0 + 48), Sse2.LoadVector128(b1 + 48))) != mask)
        {
            return false;
        }
        b0 += 64;
        b1 += 64;
    }
    while (b0 < lastAddr)
    {
        if (*b0 != *b1) return false;
        b0++;
        b1++;
    }
    return true;
}
#endif
public static unsafe bool Compare64(byte* b0, byte* b1, int length)
{
    byte* lastAddr = b0 + length;
    byte* lastAddrMinus32 = lastAddr - 32;
    while (b0 < lastAddrMinus32) // unroll the loop so that we are comparing 32 bytes at a time.
    {
        if (*(ulong*)b0 != *(ulong*)b1) return false;
        if (*(ulong*)(b0 + 8) != *(ulong*)(b1 + 8)) return false;
        if (*(ulong*)(b0 + 16) != *(ulong*)(b1 + 16)) return false;
        if (*(ulong*)(b0 + 24) != *(ulong*)(b1 + 24)) return false;
        b0 += 32;
        b1 += 32;
    }
    while (b0 < lastAddr)
    {
        if (*b0 != *b1) return false;
        b0++;
        b1++;
    }
    return true;
}

নেট মাপ .NET 462 এর জন্য আমার পরিমাপ আলাদা হয়:
মটেলিসেক পেটর

দুটি 0-দৈর্ঘ্যের অ্যারে তুলনা করার সময় কোডটি ক্র্যাশ হয়ে যায়, কারণ পিনিংয়ের ফলে null
গ্লেন স্লেডেন

memcmp কেবল একটি ইক্যুইটি তুলনামূলক নয়। এটি কোন অবজেক্টটি বড় বা ছোট তার তথ্য সরবরাহ করে। আপনি কি এই উদ্দেশ্যে আপনার অ্যালগরিদম গ্রহণ করতে পারেন এবং কার্য সম্পাদন পরীক্ষা করতে পারেন?
নিকোলে.নেইকিয়েনকো

এটা চেয়ে দ্রুত Spanএবং memcpy?
সিল্কফায়ার

@ সিল্কফায়ার। নেট কোর 3 এবং আধুনিক সিপিইউতে, বড় অ্যারেগুলির জন্য এটি 2-3 গুণ দ্রুত হওয়া উচিত।
মিঃ অ্যান্ডারসন

6

আমি অনিরাপদ কোড ব্যবহার করব এবং forইনপ 32 পয়েন্টারগুলির সাথে তুলনা করে লুপটি চালাব।

হয়তো আপনার অ্যারেগুলি পরীক্ষা করা অকার্যকর বলে মনে করা উচিত।


5

.NET কীভাবে স্ট্রিং করে at উদাহরণস্বরূপ, আপনি দেখতে পাচ্ছেন যে এটি ইকুয়ালসেল্পার নামে একটি ব্যক্তিগত পদ্ধতি ব্যবহার করে যার "অনিরাপদ" পয়েন্টার বাস্তবায়ন রয়েছে। অভ্যন্তরীণভাবে কীভাবে জিনিসগুলি করা হয় তা দেখতে। নেট প্রতিফলক আপনার বন্ধু।

এটি বাইট অ্যারে তুলনার জন্য একটি টেমপ্লেট হিসাবে ব্যবহার করা যেতে পারে যা আমি ব্লগ পোস্টে ফাস্ট বাইট অ্যারের তুলনায় সি # তে বাস্তবায়ন করেছি । নিরাপদ বাস্তবায়ন যখন অনিরাপদ থেকে দ্রুততর হয় তা দেখার জন্য আমি কিছু প্রাথমিক প্রাথমিক মানদণ্ডও করেছি।

এটি বলেছে, আপনার যদি সত্যিই খুনি পারফরম্যান্সের প্রয়োজন না হয় তবে আমি একটি সাধারণ ফ্রুপ লুপ তুলনা করতে যাই।


3

আমি সম্পূর্ণরূপে খুশি এমন কোনও সমাধান খুঁজে পাইনি (যুক্তিসঙ্গত পারফরম্যান্স, তবে কোনও অনিরাপদ কোড / পিনভোক নয়) তাই আমি এটি নিয়ে এসেছি, আসলেই আসল কিছুই নয়, তবে কাজ করে:

    /// <summary>
    /// 
    /// </summary>
    /// <param name="array1"></param>
    /// <param name="array2"></param>
    /// <param name="bytesToCompare"> 0 means compare entire arrays</param>
    /// <returns></returns>
    public static bool ArraysEqual(byte[] array1, byte[] array2, int bytesToCompare = 0)
    {
        if (array1.Length != array2.Length) return false;

        var length = (bytesToCompare == 0) ? array1.Length : bytesToCompare;
        var tailIdx = length - length % sizeof(Int64);

        //check in 8 byte chunks
        for (var i = 0; i < tailIdx; i += sizeof(Int64))
        {
            if (BitConverter.ToInt64(array1, i) != BitConverter.ToInt64(array2, i)) return false;
        }

        //check the remainder of the array, always shorter than 8 bytes
        for (var i = tailIdx; i < length; i++)
        {
            if (array1[i] != array2[i]) return false;
        }

        return true;
    }

পারফরম্যান্স এই পৃষ্ঠার অন্যান্য কয়েকটি সমাধানের সাথে তুলনা করে:

সরল লুপ: 19837 টিক্স, 1.00

* বিটকনভার্টার: 4886 টিক্স, 4.06

অনিরাপদ কম্পিউটার: 1636 টিক্স, 12.12

ইক্যুয়ালবাইটস লং তালিকাভুক্ত: 637 টিক্স, 31.09

পি / ইনভোক মেমক্যাম্প: 369 টিক্স, 53.67

লিনকপ্যাডে পরীক্ষিত, 1000000 বাইট অভিন্ন অ্যারে (সবচেয়ে খারাপ পরিস্থিতি), প্রতিটি 500 টি পুনরাবৃত্তি।


হ্যাঁ, আমি উল্লেখ করেছি যে স্ট্যাকওভারফ্লো . com/ a / 1445280 / 4489 এর মন্তব্যে যে আমার পরীক্ষাগুলি দেখায় এটি মূল প্রশ্নে লুপের জন্য সহজ থেকে কিছুটা ধীর।
হাফথোর

তুমি কি নিশ্চিত? আমার পরীক্ষায় এটি 4 গুণ দ্রুত? ওভারহেড মার্শালিংয়ের পরেও কোনও কিছুই ভাল পুরানো নেটিভ কোডটি বীট করে না।
জার শারদান

3

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

এড়িয়ে যাওয়া পদ্ধতিগুলি (গণ্যমান্য.সেকুয়েন্সএকুয়াল, স্ট্রাকচারালকম্পারাইসনস। স্ট্রাকচারালএকোয়ালিটি কমপায়ারআরকুইলস), ধৈর্যশীল ছিল না। 265MB অ্যারেতে আমি এটি পরিমাপ করেছি:

Host Process Environment Information:
BenchmarkDotNet.Core=v0.9.9.0
OS=Microsoft Windows NT 6.2.9200.0
Processor=Intel(R) Core(TM) i7-3770 CPU 3.40GHz, ProcessorCount=8
Frequency=3323582 ticks, Resolution=300.8802 ns, Timer=TSC
CLR=MS.NET 4.0.30319.42000, Arch=64-bit RELEASE [RyuJIT]
GC=Concurrent Workstation
JitModules=clrjit-v4.6.1590.0

Type=CompareMemoriesBenchmarks  Mode=Throughput  

                 Method |      Median |    StdDev | Scaled | Scaled-SD |
----------------------- |------------ |---------- |------- |---------- |
             NewMemCopy |  30.0443 ms | 1.1880 ms |   1.00 |      0.00 |
 EqualBytesLongUnrolled |  29.9917 ms | 0.7480 ms |   0.99 |      0.04 |
          msvcrt_memcmp |  30.0930 ms | 0.2964 ms |   1.00 |      0.03 |
          UnsafeCompare |  31.0520 ms | 0.7072 ms |   1.03 |      0.04 |
       ByteArrayCompare | 212.9980 ms | 2.0776 ms |   7.06 |      0.25 |

OS=Windows
Processor=?, ProcessorCount=8
Frequency=3323582 ticks, Resolution=300.8802 ns, Timer=TSC
CLR=CORE, Arch=64-bit ? [RyuJIT]
GC=Concurrent Workstation
dotnet cli version: 1.0.0-preview2-003131

Type=CompareMemoriesBenchmarks  Mode=Throughput  

                 Method |      Median |    StdDev | Scaled | Scaled-SD |
----------------------- |------------ |---------- |------- |---------- |
             NewMemCopy |  30.1789 ms | 0.0437 ms |   1.00 |      0.00 |
 EqualBytesLongUnrolled |  30.1985 ms | 0.1782 ms |   1.00 |      0.01 |
          msvcrt_memcmp |  30.1084 ms | 0.0660 ms |   1.00 |      0.00 |
          UnsafeCompare |  31.1845 ms | 0.4051 ms |   1.03 |      0.01 |
       ByteArrayCompare | 212.0213 ms | 0.1694 ms |   7.03 |      0.01 |

আমি NewMemCmpAVX-2 ব্যবহারের জন্য আমার উত্তর আপডেট করেছি
মিঃ অ্যান্ডারসন

3

আমি এখানে অনেকগুলি লিনক সমাধান দেখিনি।

আমি পারফরম্যান্সের প্রভাবগুলি সম্পর্কে নিশ্চিত নই, তবে আমি সাধারণত linqথাম্বের নিয়ম হিসাবে লেগে থাকি এবং পরে প্রয়োজনে পরে অনুকূলিত।

public bool CompareTwoArrays(byte[] array1, byte[] array2)
 {
   return !array1.Where((t, i) => t != array2[i]).Any();
 }

দয়া করে মনে রাখবেন যে এগুলি কেবল একই আকারের অ্যারে হলে কাজ করে। একটি এক্সটেনশন যেমন দেখতে পারে

public bool CompareTwoArrays(byte[] array1, byte[] array2)
 {
   if (array1.Length != array2.Length) return false;
   return !array1.Where((t, i) => t != array2[i]).Any();
 }

প্রশ্নের পুরো পয়েন্টটি একটি দ্রুত সমাধান যা ফাংশনটি প্রশ্নটিতে পোস্ট করেছে।
কোডসইনচাউস

3

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

StructuralComparison :              4.6 MiB/s
for                  :            274.5 MiB/s
ToUInt32             :            263.6 MiB/s
ToUInt64             :            474.9 MiB/s
memcmp               :           8500.8 MiB/s

আপনি দেখতে পাচ্ছেন, এর চেয়ে ভাল আর কোনও উপায় নেই memcmpএবং এটির প্রশস্ততার অর্ডার দ্রুত। একটি সাধারণ forলুপ দ্বিতীয় সেরা বিকল্প। মাইক্রোসফ্ট কেন কেবল একটি Buffer.Compareপদ্ধতি অন্তর্ভুক্ত করতে পারে না এবং এটি এখনও আমার মনকে ঘিরে ফেলেছে ।

[Program.cs]:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace memcmp
{
    class Program
    {
        static byte[] TestVector(int size)
        {
            var data = new byte[size];
            using (var rng = new System.Security.Cryptography.RNGCryptoServiceProvider())
            {
                rng.GetBytes(data);
            }
            return data;
        }

        static TimeSpan Measure(string testCase, TimeSpan offset, Action action, bool ignore = false)
        {
            var t = Stopwatch.StartNew();
            var n = 0L;
            while (t.Elapsed < TimeSpan.FromSeconds(10))
            {
                action();
                n++;
            }
            var elapsed = t.Elapsed - offset;
            if (!ignore)
            {
                Console.WriteLine($"{testCase,-16} : {n / elapsed.TotalSeconds,16:0.0} MiB/s");
            }
            return elapsed;
        }

        [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern int memcmp(byte[] b1, byte[] b2, long count);

        static void Main(string[] args)
        {
            // how quickly can we establish if two sequences of bytes are equal?

            // note that we are testing the speed of different comparsion methods

            var a = TestVector(1024 * 1024); // 1 MiB
            var b = (byte[])a.Clone();

            // was meant to offset the overhead of everything but copying but my attempt was a horrible mistake... should have reacted sooner due to the initially ridiculous throughput values...
            // Measure("offset", new TimeSpan(), () => { return; }, ignore: true);
            var offset = TimeZone.Zero

            Measure("StructuralComparison", offset, () =>
            {
                StructuralComparisons.StructuralEqualityComparer.Equals(a, b);
            });

            Measure("for", offset, () =>
            {
                for (int i = 0; i < a.Length; i++)
                {
                    if (a[i] != b[i]) break;
                }
            });

            Measure("ToUInt32", offset, () =>
            {
                for (int i = 0; i < a.Length; i += 4)
                {
                    if (BitConverter.ToUInt32(a, i) != BitConverter.ToUInt32(b, i)) break;
                }
            });

            Measure("ToUInt64", offset, () =>
            {
                for (int i = 0; i < a.Length; i += 8)
                {
                    if (BitConverter.ToUInt64(a, i) != BitConverter.ToUInt64(b, i)) break;
                }
            });

            Measure("memcmp", offset, () =>
            {
                memcmp(a, b, a.Length);
            });
        }
    }
}

2

শর্ট বাইট অ্যারে তুলনা করার জন্য নিম্নলিখিতটি একটি আকর্ষণীয় হ্যাক:

if(myByteArray1.Length != myByteArray2.Length) return false;
if(myByteArray1.Length == 8)
   return BitConverter.ToInt64(myByteArray1, 0) == BitConverter.ToInt64(myByteArray2, 0); 
else if(myByteArray.Length == 4)
   return BitConverter.ToInt32(myByteArray2, 0) == BitConverter.ToInt32(myByteArray2, 0); 

তারপরে আমি সম্ভবত প্রশ্নের তালিকাভুক্ত সমাধানে পড়ে যাব।

এই কোডটির একটি পারফরম্যান্স বিশ্লেষণ করা আকর্ষণীয় হবে।


int i = 0; (; i <a1.Length-7; i + = 8) যদি (BitConverter.ToInt64 (a1, i)! = BitConverter.ToInt64 (a2, i)) মিথ্যা ফিরে আসে; (; i <a1. দৈর্ঘ্য; i ++) যদি (a1 [i]! = a2 [i]) মিথ্যা ফিরে আসে; সত্য প্রত্যাবর্তন; // লুপের জন্য সহজ থেকে কিছুটা ধীর।
হাফথর

2

আপনারা যারা অর্ডার সম্পর্কে উদ্বিগ্ন তাদের জন্য (উদাহরণস্বরূপ আপনার কিছুই চাইলে এটির মতো memcmpফেরত চান int), নেট কোর 3.0.০ (এবং সম্ভবতঃ নেট স্ট্যান্ডার্ড ২.১ ওরফে নেট নেট .0.০) একটি Span.SequenceCompareTo(...)এক্সটেনশন পদ্ধতি (প্লাস এ Span.SequenceEqualTo) অন্তর্ভুক্ত করবে যা দুটি ReadOnlySpan<T>দৃষ্টান্ত তুলনা করতে ব্যবহার করুন ( where T: IComparable<T>)।

ইন মূল GitHub প্রস্তাব , আলোচনা, লাফ টেবিল গণনার সঙ্গে পদ্ধতির তুলনা অন্তর্ভুক্ত একটি পড়া byte[]যেমন long[], SIMD ব্যবহার, এবং P / CLR বাস্তবায়ন এর ডাকা memcmp

এগিয়ে যেতে, বাইট অ্যারে বা বাইট রেঞ্জের তুলনা করার জন্য এটি আপনার যেতে যাওয়া পদ্ধতি হওয়া উচিত ( আপনার। নেট স্ট্যান্ডার্ড ২.১ এপিআইয়ের Span<byte>পরিবর্তে ব্যবহার করা উচিত byte[]) এবং এটি যথেষ্ট দ্রুতগতির যে আপনার আর এটি অনুকূলকরণের বিষয়ে যত্ন নেওয়া উচিত নয় (এবং না, নামের সাথে সাদৃশ্য থাকা সত্ত্বেও এটি ভয়াবহর মতো অসাধ্য কাজ করে না Enumerable.SequenceEqual)।

#if NETCOREAPP3_0
// Using the platform-native Span<T>.SequenceEqual<T>(..)
public static int Compare(byte[] range1, int offset1, byte[] range2, int offset2, int count)
{
    var span1 = range1.AsSpan(offset1, count);
    var span2 = range2.AsSpan(offset2, count);

    return span1.SequenceCompareTo(span2);
    // or, if you don't care about ordering
    // return span1.SequenceEqual(span2);
}
#else
// The most basic implementation, in platform-agnostic, safe C#
public static bool Compare(byte[] range1, int offset1, byte[] range2, int offset2, int count)
{
    // Working backwards lets the compiler optimize away bound checking after the first loop
    for (int i = count - 1; i >= 0; --i)
    {
        if (range1[offset1 + i] != range2[offset2 + i])
        {
            return false;
        }
    }

    return true;
}
#endif

1

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

উপরে দেখানো পদ্ধতির অনুরূপ অপ্টিমাইজেশনের আরেকটি উপায় হ'ল প্রথম থেকে বাইট [] এর চেয়ে লম্বা [] যতটা সম্ভব আপনার ডেটা সংরক্ষণ করা, উদাহরণস্বরূপ যদি আপনি এটি বাইনারি ফাইল থেকে ধারাবাহিকভাবে পড়ছেন, অথবা আপনি যদি মেমরি ম্যাপযুক্ত ফাইল ব্যবহার করেন তবে ডেটাতে দীর্ঘ [] বা একক দীর্ঘ মান পড়ুন। তারপরে, আপনার তুলনা লুপটি একই পরিমাণে ডেটা সমেত একটি বাইট [] এর জন্য করতে হবে এমন পুনরাবৃত্তির সংখ্যার 1/8 তম প্রয়োজন। কখন এবং কতবার আপনার তুলনা করা দরকার তা একটি বিষয় যা কখন এবং কতবার আপনার বাইট-বাই-বাইট পদ্ধতিতে ডেটা অ্যাক্সেস করতে হবে, উদাহরণস্বরূপ কোনও পদ্ধতিতে এটি কোনও প্যারামিটার হিসাবে কোনও এপিআই কল এ ব্যবহার করতে হবে একটি বাইট []। শেষ পর্যন্ত, আপনি কেবলমাত্র যদি আপনি সত্যিই ব্যবহারের ক্ষেত্রে জানেন তবেই বলতে পারবেন ...


গৃহীত উত্তরটি বাইট বাফারকে একটি দীর্ঘ বাফার হিসাবে পুনরুদ্ধার করে এবং আপনার বর্ণনা অনুসারে এটি তুলনা করে।
হাফথর

1

এটি এখানে প্রদত্ত যে কোনও সংস্করণের চেয়ে প্রায় ধীরে ধীরে, তবে এটি লিখতে মজাদার was

static bool ByteArrayEquals(byte[] a1, byte[] a2) 
{
    return a1.Zip(a2, (l, r) => l == r).All(x => x);
}

1

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

public enum CompareDirection { Forward, Backward }

private static unsafe bool UnsafeEquals(byte[] a, byte[] b, CompareDirection direction = CompareDirection.Forward)
{
    // returns when a and b are same array or both null
    if (a == b) return true;

    // if either is null or different lengths, can't be equal
    if (a == null || b == null || a.Length != b.Length)
        return false;

    const int UNROLLED = 16;                // count of longs 'unrolled' in optimization
    int size = sizeof(long) * UNROLLED;     // 128 bytes (min size for 'unrolled' optimization)
    int len = a.Length;
    int n = len / size;         // count of full 128 byte segments
    int r = len % size;         // count of remaining 'unoptimized' bytes

    // pin the arrays and access them via pointers
    fixed (byte* pb_a = a, pb_b = b)
    {
        if (r > 0 && direction == CompareDirection.Backward)
        {
            byte* pa = pb_a + len - 1;
            byte* pb = pb_b + len - 1;
            byte* phead = pb_a + len - r;
            while(pa >= phead)
            {
                if (*pa != *pb) return false;
                pa--;
                pb--;
            }
        }

        if (n > 0)
        {
            int nOffset = n * size;
            if (direction == CompareDirection.Forward)
            {
                long* pa = (long*)pb_a;
                long* pb = (long*)pb_b;
                long* ptail = (long*)(pb_a + nOffset);
                while (pa < ptail)
                {
                    if (*(pa + 0) != *(pb + 0) || *(pa + 1) != *(pb + 1) ||
                        *(pa + 2) != *(pb + 2) || *(pa + 3) != *(pb + 3) ||
                        *(pa + 4) != *(pb + 4) || *(pa + 5) != *(pb + 5) ||
                        *(pa + 6) != *(pb + 6) || *(pa + 7) != *(pb + 7) ||
                        *(pa + 8) != *(pb + 8) || *(pa + 9) != *(pb + 9) ||
                        *(pa + 10) != *(pb + 10) || *(pa + 11) != *(pb + 11) ||
                        *(pa + 12) != *(pb + 12) || *(pa + 13) != *(pb + 13) ||
                        *(pa + 14) != *(pb + 14) || *(pa + 15) != *(pb + 15)
                    )
                    {
                        return false;
                    }
                    pa += UNROLLED;
                    pb += UNROLLED;
                }
            }
            else
            {
                long* pa = (long*)(pb_a + nOffset);
                long* pb = (long*)(pb_b + nOffset);
                long* phead = (long*)pb_a;
                while (phead < pa)
                {
                    if (*(pa - 1) != *(pb - 1) || *(pa - 2) != *(pb - 2) ||
                        *(pa - 3) != *(pb - 3) || *(pa - 4) != *(pb - 4) ||
                        *(pa - 5) != *(pb - 5) || *(pa - 6) != *(pb - 6) ||
                        *(pa - 7) != *(pb - 7) || *(pa - 8) != *(pb - 8) ||
                        *(pa - 9) != *(pb - 9) || *(pa - 10) != *(pb - 10) ||
                        *(pa - 11) != *(pb - 11) || *(pa - 12) != *(pb - 12) ||
                        *(pa - 13) != *(pb - 13) || *(pa - 14) != *(pb - 14) ||
                        *(pa - 15) != *(pb - 15) || *(pa - 16) != *(pb - 16)
                    )
                    {
                        return false;
                    }
                    pa -= UNROLLED;
                    pb -= UNROLLED;
                }
            }
        }

        if (r > 0 && direction == CompareDirection.Forward)
        {
            byte* pa = pb_a + len - r;
            byte* pb = pb_b + len - r;
            byte* ptail = pb_a + len;
            while(pa < ptail)
            {
                if (*pa != *pb) return false;
                pa++;
                pb++;
            }
        }
    }

    return true;
}

0

দুঃখিত, আপনি যদি ইতিমধ্যে এটি সঠিকভাবে এবং আমার জ্ঞানের সাথে চালিত কোনও ব্যবস্থাপনার সন্ধান করছেন তবে এটি করার জন্য ছাত্রলীগের কোনও পদ্ধতিই নেই।

আপনার কিছু প্রাথমিক নাল চেক যুক্ত করা উচিত এবং তারপরে এটি কেবল পুনরায় ব্যবহার করুন যেন এটি বিসিএলে রয়েছে।


আপনি যখন লিখেছিলেন ঠিকই বলেছেন, তবে ২০১০ সালে (.NET 4.0) একটি ছাত্রলীগের পদ্ধতি এসেছিল, দেখুন ওহাদ স্নাইডারের উত্তর। প্রশ্নের সময়, .NET 3.5 এর লিঙ্ক ছিল (আকুর উত্তর দেখুন)।
জেপ্পে স্টিগ নীলসেন

-1

SequenceEqualsতুলনা করার জন্য এটি ব্যবহার করুন ।


-2

আপনি যদি খুব দ্রুত বাইট অ্যারের সমতা তুলনামূলক সন্ধান করে থাকেন তবে আমি আপনাকে এই এসটিএসডিবি ল্যাবস নিবন্ধটি দেখে নিন: বাইট অ্যারে সমতা তুলনাকারী। এটিতে বাইট [] অ্যারের সমতার তুলনা করার জন্য দ্রুততম কয়েকটি বাস্তবায়ন রয়েছে, যা উপস্থাপিত হয়, পারফরম্যান্স পরীক্ষিত হয় এবং সংক্ষিপ্ত হয়।

আপনি এই বাস্তবায়নগুলিতেও মনোনিবেশ করতে পারেন:

BigEndianByteArrayComparer - দ্রুত বাইট [] অ্যারে comparer অধিকার (BigEndian) বাঁ দিক থেকে BigEndianByteArrayEqualityComparer - - দ্রুত বাইট [] সমতা comparer অধিকার (BigEndian) বাঁ দিক থেকে LittleEndianByteArrayComparer - দ্রুত বাইট [] বামে (LittleEndian) এর ডান দিক থেকে অ্যারের comparer LittleEndianByteArrayEqualityComparer - দ্রুত বাইট [] সমান তুলনা করে ডান থেকে বামে (লিটল ইন্ডিয়ান)


-2

সংক্ষিপ্ত উত্তরটি হ'ল:

    public bool Compare(byte[] b1, byte[] b2)
    {
        return Encoding.ASCII.GetString(b1) == Encoding.ASCII.GetString(b2);
    }

এইভাবে আপনি অনিরাপদ কোড না লেখার প্রয়োজন ব্যতীত বাইট অ্যারে তুলনা করতে অনুকূলিত .NET স্ট্রিং তুলনা ব্যবহার করতে পারেন use এটি পটভূমিতে এটি করা হয় :

private unsafe static bool EqualsHelper(String strA, String strB)
{
    Contract.Requires(strA != null);
    Contract.Requires(strB != null);
    Contract.Requires(strA.Length == strB.Length);

    int length = strA.Length;

    fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
    {
        char* a = ap;
        char* b = bp;

        // Unroll the loop

        #if AMD64
            // For the AMD64 bit platform we unroll by 12 and
            // check three qwords at a time. This is less code
            // than the 32 bit case and is shorter
            // pathlength.

            while (length >= 12)
            {
                if (*(long*)a     != *(long*)b)     return false;
                if (*(long*)(a+4) != *(long*)(b+4)) return false;
                if (*(long*)(a+8) != *(long*)(b+8)) return false;
                a += 12; b += 12; length -= 12;
            }
       #else
           while (length >= 10)
           {
               if (*(int*)a != *(int*)b) return false;
               if (*(int*)(a+2) != *(int*)(b+2)) return false;
               if (*(int*)(a+4) != *(int*)(b+4)) return false;
               if (*(int*)(a+6) != *(int*)(b+6)) return false;
               if (*(int*)(a+8) != *(int*)(b+8)) return false;
               a += 10; b += 10; length -= 10;
           }
       #endif

        // This depends on the fact that the String objects are
        // always zero terminated and that the terminating zero is not included
        // in the length. For odd string sizes, the last compare will include
        // the zero terminator.
        while (length > 0)
        {
            if (*(int*)a != *(int*)b) break;
            a += 2; b += 2; length -= 2;
        }

        return (length <= 0);
    }
}

আমার পরীক্ষাগুলিতে, একটি স্ট্রিংতে রূপান্তর দ্রুত তুলনার সুবিধাটিকে ধ্বংস করে। এটি লুপের জন্য প্রায় 2.5 গুণ ধীর ছিল slow
ডগ ক্লাটার

যখন আমি একইটি করতাম তখন প্রায় 8 গুণ ধীর ছিল। আপনি কি এখানে আপনার কোড লিখতে পারেন?
অ্যালন

1
যদি কোনও বাইটে একটি নাল (0) মান থাকে তবে কি এই ব্রেক হবে?
জোসেফ লেনাক্স

-1 পাশাপাশি @ ডউগক্লুটার দ্বারা নির্দেশিত স্ট্রিং-এ রূপান্তরকরণের কারণে ধীরগতির পাশাপাশি, বাইট অ্যারেটিতে অ-এএসসিআইআই ডেটা থাকলে এটি ব্যর্থ হবে। সঠিক ফলাফল পেতে আইসো -8859-1 ব্যবহার করা দরকার।
জো

2
Compare(new byte[]{128}, new byte[]{ 255 }) == trueমোটেও বগি নয় ...
কোডসইনচাউস

-2

যেহেতু উপরের অনেক অভিনব সমাধানগুলি ইউডাব্লুপি-র সাথে কাজ করে না এবং আমি লিনক এবং কার্যকরী পদ্ধতিকে ভালবাসি বলেই আমি আপনাকে এই সমস্যার জন্য আমার সংস্করণটি উপস্থাপন করি। প্রথম পার্থক্য দেখা দিলে তুলনা থেকে বাঁচতে আমি বেছে নিয়েছি। ফার্স্টআরডিফল্ট ()

public static bool CompareByteArrays(byte[] ba0, byte[] ba1) =>
    !(ba0.Length != ba1.Length || Enumerable.Range(1,ba0.Length)
        .FirstOrDefault(n => ba0[n] != ba1[n]) > 0);

-1 কারণ এই কোডটি ভাঙ্গা এবং দৃশ্যত অনির্ধারিত। IndexOutOfRangeExceptionখালি খালি অ্যারেগুলির তুলনা করার সময় এটি নিক্ষেপ করে কারণ আপনি যখন উপাদানগুলি 1অতিক্রম করতে চান ba0.Lengthতখন তার 0মধ্য দিয়ে ba0.Length - 1। যদি আপনি Enumerable.Range(0, ba0.Length)এটি স্থির করেন তবে এটি এখনও trueসমান দৈর্ঘ্যের অ্যারেগুলির জন্য ভুলভাবে ফিরে আসে যেখানে কেবল প্রথম উপাদানগুলি পৃথক হয় কারণ আপনি সন্তুষ্টকারী predicateএবং কোনও উপাদান সন্তুষ্টকারী কোনও উপাদানগুলির মধ্যে পার্থক্য করতে পারবেন না predicate; উভয় ক্ষেত্রেই FirstOrDefault<int>()ফেরত দেয় 0
বেকন

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