最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入分析java與C#底層控制能力區(qū)別及示例詳解

 更新時(shí)間:2021年11月23日 10:21:05   作者:五包辣條!  
這篇文章主要為大家深入分析java與C#底層控制能力不同的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪

大家好,我是辣條。

刷到了一個(gè)很有意思的問(wèn)題,Java和C#最大的不同是什么,辣條對(duì)Java和C#都沒(méi)有研究的特別深,但是下面這個(gè)回答可供大家參考,同時(shí)歡迎大家在評(píng)論留下自己的看法。

我覺(jué)得拋開(kāi)語(yǔ)法而談,最主要的還是對(duì)底層的控制能力不同。

比如在 C# 里面你能干的

var x = new int[10];
fixed (int* p = x)
{
    Console.WriteLine(*((long*)p - 1)); // 10
}

上述代碼會(huì)輸出 10,為什么?因?yàn)?.NET 中數(shù)組的長(zhǎng)度存儲(chǔ)于數(shù)組第一個(gè)元素之前的 8 字節(jié)內(nèi)存中。如果你再接著輸出 *((long*)p - 2),將會(huì)直接得到這個(gè)對(duì)象的 TypeHandle 地址:

Console.WriteLine((long)typeof(int[]).TypeHandle.Value == *((long*)p - 2)); // True

然后拿著這個(gè)指針又接著能去訪問(wèn)對(duì)象的 MethodTable

再有你還可以手動(dòng)在棧上分配空間

var x = stackalloc int[2]; // 或者 Span<int> x = stackalloc int[2]; 做安全訪存
x[0] = 3;
x[1] = 1;
Console.WriteLine(x[0] + x[1]); // 4

接著你想繞過(guò) GC 直接手動(dòng)分配堆內(nèi)存

var array = (int*)NativeMemory.Alloc(10, sizeof(int));
array[0] = 1;
array[1] = 3;
Console.WriteLine(array[0] + array[1]); // 4
NativeMemory.Free(array);

上述調(diào)用等價(jià)于你在 C 語(yǔ)言中調(diào)用的 malloc,此外還有 AllocAligned、ReallocAllocZeroed 等等,可以直接控制內(nèi)存對(duì)齊。

接下來(lái)你想創(chuàng)建一個(gè)顯式內(nèi)存布局的結(jié)構(gòu) Foo

var obj = new Foo();
obj.Float = 1;
Console.WriteLine(obj.Int); // 1065353216
Console.WriteLine(obj.Bytes[0]); // 0
Console.WriteLine(obj.Bytes[1]); // 0
Console.WriteLine(obj.Bytes[2]); // 128
Console.WriteLine(obj.Bytes[3]); // 63
[StructLayout(LayoutKind.Explicit)]
struct Foo
{
    [FieldOffset(0)] public int Int;
    [FieldOffset(0)] public float Float;
    [FieldOffset(0)] public unsafe fixed byte Bytes[4];
}

然后你就成功模擬出了一個(gè) C 的 Union,之所以會(huì)有上面的輸出,是因?yàn)閱尉雀↑c(diǎn)數(shù) 1 的二進(jìn)制表示為 0x00111111100000000000000000000000,以小端方式存儲(chǔ)后占 4 個(gè)字節(jié),分別是 0x000000000x000000000x10000000、0x00111111

進(jìn)一步,你還能直接從內(nèi)存數(shù)據(jù)沒(méi)有任何拷貝開(kāi)銷(xiāo)地構(gòu)造對(duì)象:

var data = stackalloc byte[] { 0, 0, 128, 63 };
var foo = Unsafe.AsRef<Foo>(data);
Console.WriteLine(foo.Float); // 1
[StructLayout(LayoutKind.Explicit)]
struct Foo
{
    [FieldOffset(0)] public int Int;
    [FieldOffset(0)] public float Float;
    [FieldOffset(0)] public unsafe fixed byte Bytes[4];
}

甚至這樣:

var data = 1065353216;
var foo = Unsafe.AsRef<Foo>(&data);
Console.WriteLine(foo.Float); // 1 
[StructLayout(LayoutKind.Explicit)]
struct Foo
{
    [FieldOffset(0)] public int Int;
    [FieldOffset(0)] public float Float;
    [FieldOffset(0)] public unsafe fixed byte Bytes[4];
}

從堆內(nèi)存創(chuàng)建自然也沒(méi)問(wèn)題

var data = new byte[] { 0, 0, 128, 63 };
fixed (void* p = data)
{
    var foo = Unsafe.AsRef<Foo>(p);
    Console.WriteLine(foo.Float); // 1
}
[StructLayout(LayoutKind.Explicit)]
struct Foo
{
    [FieldOffset(0)] public int Int;
    [FieldOffset(0)] public float Float;
    [FieldOffset(0)] public unsafe fixed byte Bytes[4];
}

再比如,此時(shí)你面前有一個(gè)使用 C++ 編寫(xiě)的庫(kù),其中有這么一段代碼:

#include <cstring>
#include <cstdio>
extern "C" __declspec(dllexport)
char* __cdecl foo(char* (*gen)(int), int count) {
    return gen(count);
}

然后我們編寫(xiě)如下 C# 代碼:

[DllImport("./foo.dll", EntryPoint = "foo"), SuppressGCTransition]
static extern string Foo(delegate* unmanaged[Cdecl]<int, nint> gen, int count);
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) }), SuppressGCTransition]
static nint Generate(int count)
{
    var str = Enumerable.Repeat("w", count).Aggregate((a, b) => $"{a}");
    return Marshal.StringToHGlobalAnsi(str);
} 
var f = (delegate* unmanaged[Cdecl]<int, nint>)&Generate;
var result = Foo(f, 5);
Console.WriteLine(result); // wwwww

上面的代碼干了什么事情?我們將 C# 的函數(shù)指針傳到了 C++ 代碼中,然后在 C++ 側(cè)調(diào)用 C# 函數(shù)生成了一個(gè)字符串 wwwww,然后將這個(gè)字符串返回給 C# 側(cè)。而就算不用函數(shù)指針換成使用委托也沒(méi)有區(qū)別,因?yàn)?.NET 中的委托下面就是函數(shù)指針。

甚至,如果我們不想讓 .NET 導(dǎo)入 foo.dll,

我們想自行決定動(dòng)態(tài)庫(kù)的生命周期

還可以這么寫(xiě):

[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) }), SuppressGCTransition]
static nint Generate(int count)
{
    var str = Enumerable.Repeat("w", count).Aggregate((a, b) => $"{a}");
    return Marshal.StringToHGlobalAnsi(str);
}
var f = (delegate* unmanaged[Cdecl]<int, nint>)&Generate;
var library = NativeLibrary.Load("./foo.dll");
var foo = (delegate* unmanaged[Cdecl, SuppressGCTransition]<delegate* unmanaged[Cdecl]<int, nint>, int, string>)NativeLibrary.GetExport(library, "foo");
var result = foo(f, 5);
Console.WriteLine(result); // wwwww
NativeLibrary.Free(library);

上面這些都不是 Windows 專(zhuān)用,在 Linux、macOS 上導(dǎo)入 .so.dylib 都完全不在話下。

再有,我們有一些數(shù)據(jù)想要進(jìn)行計(jì)算,但是我們想使用 SIMD 進(jìn)行處理,那只需要這么寫(xiě):

var vec1 = Vector128.Create(1.1f, 2.2f, 3.3f, 4.4f);
var vec2 = Vector128.Create(5.5f, 6.6f, 7.7f, 8.8f);
Console.WriteLine(Calc(vec1, vec2));
float Calc(Vector128<float> l, Vector128<float> r)
{
    if (Avx2.IsSupported)
    {
        var result = Avx2.Multiply(vec1, vec2);
        float sum = 0;
        for (var i = 0; i < Vector128<float>.Count; i++) sum += result.GetElement(i);
        return sum;
    }
    else if (Rdm.IsSupported)
    {
        var result = Rdm.Multiply(vec1, vec2);
        float sum = 0;
        for (var i = 0; i < Vector128<float>.Count; i++) sum += result.GetElement(i);
        return sum;
    }
    else
    {
        float sum = 0;
        for (int i = 0; i < Vector128<float>.Count; i++)
        {
            sum += l.GetElement(i) * r.GetElement(i);
        }
        return sum;
    }
}

可以看看在 X86 平臺(tái)上生成了什么代碼:

vzeroupper	
vmovupd	xmm0, [r8]
vmulps	xmm0, xmm0, [r8+0x10]
vmovaps	xmm1, xmm0
vxorps	xmm2, xmm2, xmm2
vaddss	xmm1, xmm1, xmm2
vmovshdup	xmm2, xmm0
vaddss	xmm1, xmm2, xmm1
vunpckhps	xmm2, xmm0, xmm0
vaddss	xmm1, xmm2, xmm1
vshufps	xmm0, xmm0, xmm0, 0xff
vaddss	xmm1, xmm0, xmm1
vmovaps	xmm0, xmm1
ret

平臺(tái)判斷的分支會(huì)被 JIT 自動(dòng)消除。但其實(shí)除了手動(dòng)編寫(xiě) SIMD 代碼之外,前兩個(gè)分支完全可以不寫(xiě),而只留下:

float Calc(Vector128<float> l, Vector128<float> r)
{
    float sum = 0;
    for (int i = 0; i < Vector128<float>.Count; i++)
    {
        sum += l.GetElement(i) * r.GetElement(i);
    }
    return sum;
}

因?yàn)楝F(xiàn)階段當(dāng)循環(huán)邊界條件是向量長(zhǎng)度時(shí),.NET 會(huì)自動(dòng)為我們做向量化并展開(kāi)循環(huán)。

那么繼續(xù),我們還有ref、in、out來(lái)做引用傳遞。

假設(shè)我們有一個(gè)很大的 struct,我們?yōu)榱吮苊鈧鬟f時(shí)發(fā)生拷貝,可以直接用 in 來(lái)做只讀引用傳遞:

void Test(in Foo v) { }
struct Foo
{
    public long A, B, C, D, E, F, G, H, I, J, K, L, M, N;
}

而對(duì)于小的 struct,.NET 有專(zhuān)門(mén)的優(yōu)化幫我們徹底消除掉內(nèi)存分配,完全將 struct 放在寄存器中,例如如下代碼:

double Test(int x1, int y1, int x2, int y2)
{
    var p1 = new Point(x1, y1);
    var p2 = new Point(x2, y2);
    return GetDistance(p1, p2);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
double GetDistance(Point a, Point b)
{
    return Math.Sqrt((a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y));
}
struct Point
{
    public Point(int x, int y)
    {
        X = x; Y = y;
    }    
    public int X { get; set; }
    public int Y { get; set; }
}

上述代碼 GetDistance 考慮是個(gè)熱點(diǎn)路徑,因此我加 MethodImplOptions.AggressiveInlining 來(lái)指導(dǎo) JIT 有保證地內(nèi)聯(lián)此函數(shù),最后為 Test 生成了如下的代碼:

vzeroupper	
sub	ecx, r8d
mov	eax, ecx
imul	eax, ecx
sub	edx, r9d
mov	ecx, edx
imul	edx, ecx
add	eax, edx
vxorps	xmm0, xmm0, xmm0
vcvtsi2sd	xmm0, xmm0, eax
vsqrtsd	xmm0, xmm0, xmm0
ret

全程沒(méi)有一句指令訪存,非常的高效。

我們還可以借用 ref 的引用語(yǔ)義來(lái)做原地更新

var vec = new Vector(10);
vec[2] = 5;
Console.WriteLine(vec[2]); // 5
ref var x = ref vec[3];
x = 7;
Console.WriteLine(vec[3]); // 7
class Vector
{
    private int[] _array;
    public Vector(int count) => _array = new int[count];
    public ref int this[int index] => ref _array[index];
}

甚至還能搭配指針和手動(dòng)分配內(nèi)存來(lái)使用

var vec = new Vector(10);
vec[2] = 5;
Console.WriteLine(vec[2]); // 5
ref var x = ref vec[3];
x = 7;
Console.WriteLine(vec[3]); // 7
unsafe class Vector
{
    private int* _memory;
    public Vector(uint count) => _memory = (int*)NativeMemory.Alloc(count, sizeof(int));
    public ref int this[int index] => ref _memory[index];
    ~Vector() => NativeMemory.Free(_memory);
}

C# 的泛型不像 Java 采用擦除,而是真真正正會(huì)對(duì)所有的類(lèi)型參數(shù)特化代碼(盡管對(duì)于引用類(lèi)型會(huì)共享實(shí)現(xiàn)采用運(yùn)行時(shí)分發(fā)),這也就意味著能最大程度確保性能,并且對(duì)應(yīng)的類(lèi)型擁有根據(jù)類(lèi)型參數(shù)大小不同而特化的內(nèi)存布局。還是上面那個(gè) Point 的例子,我們將下面的數(shù)據(jù) int 換成泛型參數(shù) T,并做值類(lèi)型數(shù)字的泛型約束:

double Test1(double x1, double y1, double x2, double y2)
{
    var p1 = new Point<double>(x1, y1);
    var p2 = new Point<double>(x2, y2);
    var result = GetDistanceSquare(p1, p2);
    return Math.Sqrt(result);
}
double Test2(int x1, int y1, int x2, int y2)
{
    var p1 = new Point<int>(x1, y1);
    var p2 = new Point<int>(x2, y2);
    var result = GetDistanceSquare(p1, p2);
    return Math.Sqrt(result);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
T GetDistanceSquare<T>(Point<T> a, Point<T> b) where T : struct, IBinaryNumber<T>
{
    return (a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y);
}
struct Point<T> where T : struct, IBinaryNumber<T>
{
    public Point(T x, T y)
    {
        X = x; Y = y;
    }
 
    public T X { get; set; }
    public T Y { get; set; }
}

無(wú)論是 Test1 還是 Test2,生成的代碼都非常優(yōu)秀,不僅不存在任何的裝箱拆箱,甚至沒(méi)有任何的訪存操作:

' Test1
vzeroupper	
vsubsd	xmm0, xmm0, xmm2
vmovaps	xmm2, xmm0
vmulsd	xmm0, xmm0, xmm2
vsubsd	xmm1, xmm1, xmm3
vmovaps	xmm2, xmm1
vmulsd	xmm1, xmm1, xmm2
vaddsd	xmm0, xmm1, xmm0
vsqrtsd	xmm0, xmm0, xmm0
ret	
 
' Test2
vzeroupper	
sub	ecx, r8d
mov	eax, ecx
imul	eax, ecx
sub	edx, r9d
mov	ecx, edx
imul	edx, ecx
add	eax, edx
vxorps	xmm0, xmm0, xmm0
vcvtsi2sd	xmm0, xmm0, eax
vsqrtsd	xmm0, xmm0, xmm0
ret

接著講,我們有時(shí)候?yàn)榱烁咝阅芟胍R時(shí)暫停 GC 的回收,只需要簡(jiǎn)單的一句:

GC.TryStartNoGCRegion(1024 * 1024 * 128);

就能告訴 GC 如果還能分配 128mb 內(nèi)存那就不要做回收了,然后一段時(shí)間內(nèi)以后的代碼我們盡管在這個(gè)預(yù)算內(nèi)分配內(nèi)存,任何 GC 都不會(huì)發(fā)生。甚至還能阻止在內(nèi)存不夠分配的情況下進(jìn)行阻塞式 Full GC:

GC.TryStartNoGCRegion(1024 * 1024 * 128, true);

代碼執(zhí)行完了,最后的時(shí)候調(diào)用一句:

GC.EndNoGCRegion();

即可恢復(fù) GC 行為。

除此之外,我們還能在運(yùn)行時(shí)指定 GC 的模式來(lái)最大化性能:

GCSettings.LatencyMode = GCLatencyMode.Batch;
GCSettings.LatencyMode = GCLatencyMode.Interactive;
GCSettings.LatencyMode = GCLatencyMode.LowLatency;
GCSettings.LatencyMode = GCLatencyMode.NoGCRegion;
GCSettings.LatencyMode = GCLatencyMode.SustainedLowLatency;

更進(jìn)一步,我們甚至可以直接將堆內(nèi)存中的代碼執(zhí)行,在 .NET 上自己造一個(gè) JIT,直接從內(nèi)存創(chuàng)建一塊可執(zhí)行的區(qū)域然后往里面塞一段代碼用來(lái)將兩個(gè)32位整數(shù)相加:

var kernel32 = NativeLibrary.Load("kernel32.dll");
var virtualProtectEx = (delegate* unmanaged[Cdecl, SuppressGCTransition]<nint, void*, nint, int, out int, bool>)NativeLibrary.GetExport(kernel32, "VirtualProtectEx");
var processHandle = Process.GetCurrentProcess().Handle;
Memory<byte> code = new byte[] {
    0x8d, 0x04, 0x11, // lea rax, [rcx+rdx]
    0xc3              // ret
}
using (var handle = code.Pin())
{
    virtualProtectEx(processHandle, handle.Pointer, code.Length, 0x40, out _);
    var f = (delegate*<int, int, int>)handle.Pointer;
    Console.WriteLine(f(2, 3)); // 5
}
virtualProtectEx = null;
NativeLibrary.Free(kernel32);

除此之外,C# 還有更多數(shù)不清的底層寫(xiě)法來(lái)和操作系統(tǒng)交互,甚至利用 C# 的編譯器取消鏈接到自己的標(biāo)準(zhǔn)庫(kù),直接用從 0 開(kāi)始造基礎(chǔ)類(lèi)型然后通過(guò) NativeAOT 編譯出完全無(wú) GC、能夠在裸機(jī)硬件上執(zhí)行引導(dǎo)系統(tǒng)的 EFI 固件都是沒(méi)有問(wèn)題的。

另外還有 ILGPU 讓你把 C# 代碼直接跑在 GPU 上面,以及跑在嵌入式設(shè)備上直接操作 I2C、PWM、GPIO 等等,就不再舉例子了。

而 C# 已經(jīng)進(jìn)了 roadmap 的后續(xù)更新內(nèi)容:允許聲明引用字段、添加表達(dá)固定長(zhǎng)度內(nèi)存的類(lèi)型、允許傳數(shù)組時(shí)消除數(shù)組分配、允許在棧上分配任何對(duì)象等等,無(wú)一不是在改進(jìn)這些底層性能設(shè)施。

以上就是我認(rèn)為的 C# 和 Java 最大的不同。

在 C# 中當(dāng)你不需要上面這些的東西時(shí),它們仿佛從來(lái)都不存在,允許動(dòng)態(tài)類(lèi)型、不斷吸收各種函數(shù)式特性、還有各種語(yǔ)法糖加持,簡(jiǎn)潔度和靈活度甚至不輸 Python,非常愉快和簡(jiǎn)單地就能編寫(xiě)各種代碼;而一旦你需要,你可以擁有從上層到底層的幾乎完全的控制能力,而這些能力將能讓你有需要時(shí)無(wú)需思考各種奇怪的 workaround 就能直接榨干機(jī)器,達(dá)到 C、C++ 的性能,甚至因?yàn)橛羞\(yùn)行時(shí) PGO 而超出 C、C++ 的性能。

以上就是深入分析java與C#底層控制能力不同的詳細(xì)內(nèi)容,更多關(guān)于java與C#底層控制能力不同分析的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 計(jì)算機(jī)網(wǎng)絡(luò)編程MQTT協(xié)議基礎(chǔ)原理詳解

    計(jì)算機(jī)網(wǎng)絡(luò)編程MQTT協(xié)議基礎(chǔ)原理詳解

    這篇文章主要為大家介紹了計(jì)算機(jī)編程MQTT協(xié)議的基礎(chǔ)原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2021-11-11
  • DLL(Dynamic Linkable Library) 詳解說(shuō)明

    DLL(Dynamic Linkable Library) 詳解說(shuō)明

    DLL文件(Dynamic Linkable Library 即動(dòng)態(tài)鏈接庫(kù)文件),是一種不能單獨(dú)運(yùn)行的文件,它允許程序共享執(zhí)行特殊任務(wù)所必需的代碼和其他資源
    2008-12-12
  • H5混合開(kāi)發(fā)手機(jī)Web App入門(mén):概念篇

    H5混合開(kāi)發(fā)手機(jī)Web App入門(mén):概念篇

    如果你開(kāi)始學(xué)習(xí)手機(jī) App 開(kāi)發(fā),就一定會(huì)聽(tīng)到 H5 這個(gè)詞。它是目前的主流開(kāi)發(fā)技術(shù)之一,容易上手,開(kāi)發(fā)周期短、成本低、兼容傳統(tǒng) Web 開(kāi)發(fā)。但是,很少有文章詳細(xì)介紹,H5 到底是什么技術(shù),有什么原理,跟其他技術(shù)的差異在哪里。
    2022-12-12
  • 作為程序員必須了解的縮寫(xiě)和專(zhuān)業(yè)名詞

    作為程序員必須了解的縮寫(xiě)和專(zhuān)業(yè)名詞

    這篇文章主要介紹了作為程序員必須了解的縮寫(xiě)和專(zhuān)業(yè)名詞,文中講解非常詳細(xì),對(duì)想學(xué)編程的朋友有所幫助,感興趣的可以了解下
    2020-07-07
  • vscode配置備份的操作代碼

    vscode配置備份的操作代碼

    這篇文章主要介紹了vscode配置備份的相關(guān)知識(shí),本文通過(guò)實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • electron桌面應(yīng)用程序搭建及簡(jiǎn)單運(yùn)行

    electron桌面應(yīng)用程序搭建及簡(jiǎn)單運(yùn)行

    這篇文章主要介紹了electron桌面應(yīng)用程序搭建及運(yùn)行,需要的朋友可以參考下
    2022-12-12
  • 單點(diǎn)登錄的三種實(shí)現(xiàn)方式

    單點(diǎn)登錄的三種實(shí)現(xiàn)方式

    這篇文章主要介紹了單點(diǎn)登錄的三種實(shí)現(xiàn)方式,幫助大家建立網(wǎng)站,優(yōu)化網(wǎng)站體驗(yàn),感興趣的朋友可以了解下
    2020-09-09
  • 匯編語(yǔ)言無(wú)效指令錯(cuò)誤概述

    匯編語(yǔ)言無(wú)效指令錯(cuò)誤概述

    此錯(cuò)誤僅適用于奔騰 處理器、奔騰處理器與MMX技術(shù)、奔騰OverDrive處理器 和奔騰OverDrive處理器帶有MMX技術(shù)。 奔騰Pro處理器, 奔騰II處理器和i486及更早版本處理器不受影響
    2012-07-07
  • ffmpeg播放器實(shí)現(xiàn)詳解之視頻顯示(推薦)

    ffmpeg播放器實(shí)現(xiàn)詳解之視頻顯示(推薦)

    FFmpeg是一套可以用來(lái)記錄、轉(zhuǎn)換數(shù)字音頻、視頻,并能將其轉(zhuǎn)化為流的開(kāi)源計(jì)算機(jī)程序。這篇文章主要介紹了ffmpeg播放器實(shí)現(xiàn)詳解視頻顯示,需要的朋友可以參考下
    2020-07-07
  • Matlab使用fft畫(huà)出信號(hào)頻譜圖的方法

    Matlab使用fft畫(huà)出信號(hào)頻譜圖的方法

    這篇文章主要介紹了Matlab使用fft畫(huà)出信號(hào)頻譜圖的方法,本文通過(guò)實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04

最新評(píng)論

阿巴嘎旗| 台安县| 大安市| 巩留县| 靖西县| 慈溪市| 定襄县| 珲春市| 辉南县| 齐河县| 河西区| 大丰市| 左云县| 府谷县| 武威市| 府谷县| 当涂县| 虹口区| 和田市| 盐城市| 渑池县| 开江县| 绥滨县| 潮安县| 玉龙| 阿图什市| 河南省| 南雄市| 炎陵县| 林州市| 灵川县| 永靖县| 晋州市| 德昌县| 固阳县| 徐汇区| 惠州市| 松溪县| 枣庄市| 秦皇岛市| 页游|