当前位置: 首页 > 编程日记 > 正文

wcf系列学习5天速成——第四天 wcf之分布式架构(转载)

今天是wcf系列的第四天,也该出手压轴戏了。嗯,现在的大型架构,都是神马的,

nginx鸡群,iis鸡群,wcf鸡群,DB鸡群,由一个人作战变成了群殴.......

今天我就分享下wcf鸡群,高性能架构中一种常用的手法就是在内存中维护一个叫做“索引”的内存数据库,

在实战中利用“索引”这个概念做出"海量数据“的秒杀。

好,先上图:

这个图明白人都能看得懂吧。因为我的系列偏重于wcf,所以我重点说下”心跳检测“的实战手法。

第一步:上一下项目的结构,才能做到心中有数。

第二步:“LoadDBService”这个是控制台程序,目的就是从数据库抽出关系模型加载在内存数据库中,因为这些东西会涉及一些算法的知识,

在这里就不写算法了,就简单的模拟一下。

LoadDBServcie
 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Runtime.Serialization;
6 using System.Web.Script.Serialization;
7 using System.IO;
8 using System.Xml.Serialization;
9 using System.Xml;
10 using Common;
11
12 namespace LoadDBData
13 {
14 class Program
15 {
16 static void Main(string[] args)
17 {
18 //模拟从数据库加载索引到内存中,形成内存中的数据库
19 //这里的 "Dictionary" 用来表达“一个用户注册过多少店铺“,即UserID与ShopID的一对多关系
20 SerializableDictionary<int, List<int>> dic = new SerializableDictionary<int, List<int>>();
21
22 List<int> shopIDList = new List<int>();
23
24 for (int shopID = 300000; shopID < 300050; shopID++)
25 shopIDList.Add(shopID);
26
27 int UserID = 15;
28
29 //假设这里已经维护好了UserID与ShopID的关系
30 dic.Add(UserID, shopIDList);
31
32 XmlSerializer xml = new XmlSerializer(dic.GetType());
33
34 var memoryStream = new MemoryStream();
35
36 xml.Serialize(memoryStream, dic);
37
38 memoryStream.Seek(0, SeekOrigin.Begin);
39
40 //将Dictionary持久化,相当于模拟保存在Mencache里面
41 File.AppendAllText("F://1.txt", Encoding.UTF8.GetString(memoryStream.ToArray()));
42
43 Console.WriteLine("数据加载成功!");
44
45 Console.Read();
46 }
47 }
48 }


因为Dictionary不支持序列化,所以我从网上拷贝了一份代码让其执行序列化

SerializableDictionary
  1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Xml.Serialization;
6 using System.Xml;
7 using System.Xml.Schema;
8 using System.Runtime.Serialization;
9
10 namespace Common
11 {
12 ///<summary>
13 /// 标题:支持 XML 序列化的 Dictionary
14 ///</summary>
15 ///<typeparam name="TKey"></typeparam>
16 ///<typeparam name="TValue"></typeparam>
17 [XmlRoot("SerializableDictionary")]
18 public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
19 {
20
21 public SerializableDictionary()
22 : base()
23 {
24 }
25 public SerializableDictionary(IDictionary<TKey, TValue> dictionary)
26 : base(dictionary)
27 {
28 }
29
30 public SerializableDictionary(IEqualityComparer<TKey> comparer)
31 : base(comparer)
32 {
33 }
34
35 public SerializableDictionary(int capacity)
36 : base(capacity)
37 {
38 }
39 public SerializableDictionary(int capacity, IEqualityComparer<TKey> comparer)
40 : base(capacity, comparer)
41 {
42 }
43 protected SerializableDictionary(SerializationInfo info, StreamingContext context)
44 : base(info, context)
45 {
46 }
47
48
49 public System.Xml.Schema.XmlSchema GetSchema()
50 {
51 return null;
52 }
53 ///<summary>
54 /// 从对象的 XML 表示形式生成该对象
55 ///</summary>
56 ///<param name="reader"></param>
57 public void ReadXml(System.Xml.XmlReader reader)
58 {
59 XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
60 XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
61 bool wasEmpty = reader.IsEmptyElement;
62 reader.Read();
63 if (wasEmpty)
64 return;
65 while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
66 {
67 reader.ReadStartElement("item");
68 reader.ReadStartElement("key");
69 TKey key = (TKey)keySerializer.Deserialize(reader);
70 reader.ReadEndElement();
71 reader.ReadStartElement("value");
72 TValue value = (TValue)valueSerializer.Deserialize(reader);
73 reader.ReadEndElement();
74 this.Add(key, value);
75 reader.ReadEndElement();
76 reader.MoveToContent();
77 }
78 reader.ReadEndElement();
79 }
80
81 /**/
82 ///<summary>
83 /// 将对象转换为其 XML 表示形式
84 ///</summary>
85 ///<param name="writer"></param>
86 public void WriteXml(System.Xml.XmlWriter writer)
87 {
88 XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
89 XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
90 foreach (TKey key in this.Keys)
91 {
92 writer.WriteStartElement("item");
93 writer.WriteStartElement("key");
94 keySerializer.Serialize(writer, key);
95 writer.WriteEndElement();
96 writer.WriteStartElement("value");
97 TValue value = this[key];
98 valueSerializer.Serialize(writer, value);
99 writer.WriteEndElement();
100 writer.WriteEndElement();
101 }
102 }
103
104 }
105 }


第三步: "HeartBeatService"也做成了一个控制台程序,为了图方便,把Contract和Host都放在一个控制台程序中,

代码中加入了注释,看一下就会懂的。

IAddress.cs
 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Runtime.Serialization;
5 using System.ServiceModel;
6 using System.Text;
7
8 namespace HeartBeatService
9 {
10 //CallbackContract:这个就是Client实现此接口,方便服务器端通知客户端
11 [ServiceContract(CallbackContract = typeof(ILiveAddressCallback))]
12 public interface IAddress
13 {
14 ///<summary>
15 /// 此方法用于Search启动后,将Search地址插入到此处
16 ///</summary>
17 ///<param name="address"></param>
18 [OperationContract(IsOneWay = true)]
19 void AddSearch(string address);
20
21 ///<summary>
22 /// 此方法用于IIS端获取search地址
23 ///</summary>
24 ///<param name="address"></param>
25 [OperationContract(IsOneWay = true)]
26 void GetService(string address);
27 }
28 }

Address.cs
  1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Runtime.Serialization;
5 using System.ServiceModel;
6 using System.Text;
7 using System.Timers;
8 using System.IO;
9 using System.Collections.Concurrent;
10 using SearhService;
11 using ClientService;
12
13 namespace HeartBeatService
14 {
15 //InstanceContextMode:主要是管理上下文的实例,此处是single,也就是单体
16 //ConcurrencyMode: 主要是用来控制实例中的线程数,此处是Multiple,也就是多线程
17 [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
18 public class Address : IAddress
19 {
20 static List<string> search = new List<string>();
21
22 static object obj = new object();
23
24 ///<summary>
25 /// 此静态构造函数用来检测存活的Search个数
26 ///</summary>
27 static Address()
28 {
29 Timer timer = new Timer();
30 timer.Interval = 6000;
31 timer.Elapsed += (sender, e) =>
32 {
33
34 Console.WriteLine("\n***************************************************************************");
35 Console.WriteLine("当前存活的Search为:");
36
37 lock (obj)
38 {
39 //遍历当前存活的Search
40 foreach (var single in search)
41 {
42 ChannelFactory<IProduct> factory = null;
43
44 try
45 {
46 //当Search存在的话,心跳服务就要定时检测Search是否死掉,也就是定时的连接Search来检测。
47 factory = new ChannelFactory<IProduct>(new NetTcpBinding(SecurityMode.None), new EndpointAddress(single));
48 factory.CreateChannel().TestSearch();
49 factory.Close();
50
51 Console.WriteLine(single);
52
53 }
54 catch (Exception ex)
55 {
56 Console.WriteLine(ex.Message);
57
58 //如果抛出异常,则说明此search已经挂掉
59 search.Remove(single);
60 factory.Abort();
61 Console.WriteLine("\n当前时间:" + DateTime.Now + " ,存活的Search有:" + search.Count() + "");
62 }
63 }
64 }
65
66 //最后统计下存活的search有多少个
67 Console.WriteLine("\n当前时间:" + DateTime.Now + " ,存活的Search有:" + search.Count() + "");
68 };
69 timer.Start();
70 }
71
72 public void AddSearch(string address)
73 {
74
75 lock (obj)
76 {
77 //是否包含相同的Search地址
78 if (!search.Contains(address))
79 {
80 search.Add(address);
81
82 //search添加成功后就要告诉来源处,此search已经被成功载入。
83 var client = OperationContext.Current.GetCallbackChannel<ILiveAddressCallback>();
84 client.LiveAddress(address);
85 }
86 }
87 }
88
89 public void GetService(string address)
90 {
91 Timer timer = new Timer();
92 timer.Interval = 1000;
93 timer.Elapsed += (obj, sender) =>
94 {
95 try
96 {
97 //这个是定时的检测IIS是否挂掉
98 var factory = new ChannelFactory<IServiceList>(new NetTcpBinding(SecurityMode.None),
99 new EndpointAddress(address));
100
101 factory.CreateChannel().AddSearchList(search);
102
103 factory.Close();
104
105 timer.Interval = 10000;
106 }
107 catch (Exception ex)
108 {
109 Console.WriteLine(ex.Message);
110 }
111 };
112 timer.Start();
113 }
114 }
115 }

ILiveAddressCallback.cs
 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.ServiceModel;
6
7 namespace HeartBeatService
8 {
9 ///<summary>
10 /// 等客户端实现后,让客户端约束一下,只能是这个LiveAddress方法
11 ///</summary>
12 public interface ILiveAddressCallback
13 {
14 [OperationContract(IsOneWay = true)]
15 void LiveAddress(string address);
16 }
17 }


第四步: 我们开一下心跳,预览下效果:

是的,心跳现在正在检测是否有活着的Search。

第五步:"SearhService" 这个Console程序就是WCF的search,主要用于从MemerCache里面读取索引。

记得要添加一下对“心跳服务”的服务引用。


IProduct.cs
 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Runtime.Serialization;
5 using System.ServiceModel;
6 using System.Text;
7
8 namespace SearhService
9 {
10 // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IService1”。
11 [ServiceContract]
12 public interface IProduct
13 {
14 [OperationContract]
15 List<int> GetShopListByUserID(int userID);
16
17 [OperationContract]
18 void TestSearch();
19 }
20 }

Product.cs
 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Runtime.Serialization;
5 using System.ServiceModel;
6 using System.Text;
7 using Common;
8 using System.Xml;
9 using System.IO;
10 using System.Xml.Serialization;
11
12 namespace SearhService
13 {
14 public class Product : IProduct
15 {
16 public List<int> GetShopListByUserID(int userID)
17 {
18 //模拟从MemCache中读取索引
19 SerializableDictionary<int, List<int>> dic = new SerializableDictionary<int, List<int>>();
20
21 byte[] bytes = Encoding.UTF8.GetBytes(File.ReadAllText("F://1.txt", Encoding.UTF8));
22
23 var memoryStream = new MemoryStream();
24
25 memoryStream.Write(bytes, 0, bytes.Count());
26
27 memoryStream.Seek(0, SeekOrigin.Begin);
28
29 XmlSerializer xml = new XmlSerializer(dic.GetType());
30
31 var obj = xml.Deserialize(memoryStream) as Dictionary<int, List<int>>;
32
33 return obj[userID];
34 }
35
36 public void TestSearch() { }
37 }
38 }

SearchHost.cs
 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.ServiceModel;
6 using System.Configuration;
7 using System.Timers;
8 using SearhService.HeartBeatService;
9
10 namespace SearhService
11 {
12 public class SearchHost : IAddressCallback
13 {
14 static DateTime startTime;
15
16 public static void Main()
17 {
18 ServiceHost host = new ServiceHost(typeof(Product));
19
20 host.Open();
21
22 AddSearch();
23
24 Console.Read();
25
26 }
27
28 static void AddSearch()
29 {
30 startTime = DateTime.Now;
31
32 Console.WriteLine("Search服务发送中.....\n\n*************************************************\n");
33
34 try
35 {
36 var heartClient = new AddressClient(new InstanceContext(new SearchHost()));
37
38 string search = ConfigurationManager.AppSettings["search"];
39
40 heartClient.AddSearch(search);
41 }
42 catch (Exception ex)
43 {
44 Console.WriteLine("Search服务发送失败:" + ex.Message);
45 }
46 }
47
48 public void LiveAddress(string address)
49 {
50 Console.WriteLine("恭喜你," + address + "已被心跳成功接收!\n");
51 Console.WriteLine("发送时间:" + startTime + "\n接收时间:" + DateTime.Now);
52 }
53 }
54 }

第六步:此时Search服务已经建好,我们可以测试当Search开启获取关闭对心跳有什么影响:

Search开启时:


Search关闭时:

对的,当Search关闭时,心跳检测该Search已经死掉,然后只能从集群中剔除。

当然,我们可以将Search拷贝N份,部署在N台机器中,只要修改一下endpoint地址就OK了,这一点明白人都会。

第七步:"ClientService" 这里也就指的是IIS,此时我们也要添加一下对心跳的服务引用。

IServiceList.cs
 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.ServiceModel;
6
7 namespace ClientService
8 {
9 [ServiceContract]
10 public interface IServiceList
11 {
12 [OperationContract]
13 void AddSearchList(List<string> search);
14 }
15 }

ServiceList.cs
 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.ServiceModel;
6 using System.Configuration;
7 using System.Timers;
8 using System.Threading;
9
10 namespace ClientService
11 {
12 public class ServiceList : IServiceList
13 {
14 public static List<string> searchList = new List<string>();
15
16 static object obj = new object();
17
18 public static string Search
19 {
20 get
21 {
22 lock (obj)
23 {
24 //如果心跳没及时返回地址,客户端就在等候
25 if (searchList.Count == 0)
26 Thread.Sleep(1000);
27 return searchList[new Random().Next(0, searchList.Count)];
28 }
29 }
30 set
31 {
32
33 }
34 }
35
36 public void AddSearchList(List<string> search)
37 {
38 lock (obj)
39 {
40 searchList = search;
41
42 Console.WriteLine("************************************");
43 Console.WriteLine("当前存活的Search为:");
44
45 foreach (var single in searchList)
46 {
47 Console.WriteLine(single);
48 }
49 }
50 }
51 }
52 }



Program.cs
 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.ServiceModel;
6 using System.Configuration;
7 using System.Threading;
8 using ClientService.HeartBeatService;
9 using SearhService;
10 using BaseClass;
11 using System.Data;
12 using System.Diagnostics;
13
14 namespace ClientService
15 {
16 class Program : IAddressCallback
17 {
18 static void Main(string[] args)
19 {
20
21 ServiceHost host = new ServiceHost(typeof(ServiceList));
22
23 host.Open();
24
25 var client = new AddressClient(new InstanceContext(new Program()));
26
27 //配置文件中获取iis的地址
28 var iis = ConfigurationManager.AppSettings["iis"];
29
30 //将iis的地址告诉心跳
31 client.GetService(iis);
32
33 //从集群中获取search地址来对Search服务进行调用
34 var factory = new ChannelFactory<IProduct>(new NetTcpBinding(SecurityMode.None), new EndpointAddress(ServiceList.Search));
35
36 //根据userid获取了shopID的集合
37 var shopIDList = factory.CreateChannel().GetShopListByUserID(15);
38
39 //.......................... 后续就是我们将shopIDList做连接数据库查询(做到秒杀)
40
41 Console.Read();
42 }
43
44 public void LiveAddress(string address)
45 {
46
47 }
48 }
49 }

然后我们开启Client,看看效果咋样:


当然,search集群后,client得到search的地址是随机的,也就分担了search的负担,实现有福同享,有难同当的效果了。

最后: 我们做下性能检测,看下“秒杀”和“毫秒杀”的效果。

首先在数据库的User表和Shop插入了180万和20万的数据用于关联。

ClientService改造后的代码:

Program.cs
 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.ServiceModel;
6 using System.Timers;
7 using System.Diagnostics;
8 using BaseClass;
9 using ClientService;
10 using ClientService.HeartBeatService;
11 using System.Configuration;
12 using SearhService;
13
14 namespace ClientService
15 {
16 class Program : IAddressCallback
17 {
18 static void Main(string[] args)
19 {
20
21 ServiceHost host = new ServiceHost(typeof(ServiceList));
22
23 host.Open();
24
25 var client = new AddressClient(new InstanceContext(new Program()));
26
27 //配置文件中获取iis的地址
28 var iis = ConfigurationManager.AppSettings["iis"];
29
30 //将iis的地址告诉心跳
31 client.GetService(iis);
32
33 //从集群中获取search地址来对Search服务进行调用
34 var factory = new ChannelFactory<IProduct>(new NetTcpBinding(SecurityMode.None), new EndpointAddress(ServiceList.Search));
35
36 //根据userid获取了shopID的集合
37 //比如说这里的ShopIDList是通过索引交并集获取的分页的一些shopID
38 var shopIDList = factory.CreateChannel().GetShopListByUserID(15);
39
40 var strSql = string.Join(",", shopIDList);
41
42 Stopwatch watch = new Stopwatch();
43
44 watch.Start();
45 SqlHelper.Query("select s.ShopID,u.UserName,s.ShopName from [User] as u ,Shop as s where s.ShopID in(" + strSql + ")");
46 watch.Stop();
47
48 Console.WriteLine("通过wcf索引获取的ID >>>花费时间:" + watch.ElapsedMilliseconds);
49
50 //普通的sql查询花费的时间
51 StringBuilder builder = new StringBuilder();
52
53 builder.Append("select * from ");
54 builder.Append("(select ROW_NUMBER() over(order by s.ShopID) as NumberID, ");
55 builder.Append(" s.ShopID, u.UserName, s.ShopName ");
56 builder.Append("from Shop s left join [User] as u on u.UserID=s.UserID ");
57 builder.Append("where s.UserID=15) as array ");
58 builder.Append("where NumberID>300000 and NumberID<300050");
59
60 watch.Start();
61 SqlHelper.Query(builder.ToString());
62 watch.Stop();
63
64 Console.WriteLine("普通的sql分页 >>>花费时间:" + watch.ElapsedMilliseconds);
65
66 Console.Read();
67 }
68
69 public void LiveAddress(string address)
70 {
71
72 }
73 }
74 }

性能图:

对的,一个秒杀,一个是毫秒杀,所以越复杂越能展示出“内存索引”的强大之处。

转载于:https://www.cnblogs.com/zpc870921/archive/2012/08/17/2643960.html

相关文章:

检测jQuery.js是否已加载的判断代码

转载自http://www.jb51.net/article/27185.htm 测类、方法、变量或属性是否已存在&#xff0c;这是Javascript编程基础知识。在这里我们就是要检测jQuery()或$()函数是否存在 当然&#xff0c;该方法不局限于jQuery的检测&#xff0c;对与任何Javascript变量或函数都是通用的。…

Java中常见的锁简述

在Java的应用中&#xff0c;或多或少的都会接触到一些锁&#xff0c;那么问题就来了&#xff0c;在Java中&#xff0c;常见的锁有哪些&#xff0c;都有什么样的作用&#xff1f;&#xff1f; 这里给大家简单的简述一下这些学常见的锁。 本文件所涉及到的锁&#xff1a; 1.公平锁…

加了好友怎么还掉血_微信聊天窗口出现风险提醒,无法添加好友解决办法

再更&#xff0c;你想马上解封&#xff0c;你得有朋友。没有朋友&#xff0c;你就等个十天半个月&#xff01;更新一下 帖子浏览人挺多的&#xff0c;有问题可以在评论里相互交流&#xff0c;下面是原文&#xff1a;先让我说一句脏话&#xff1a;傻x微信风控系统 终于特么的聊天…

[小明爬坑系列]AssetBundle原理介绍

一.简介 Assetbundle 是Unity Pro提供提供的功能&#xff0c;它可以把多个游戏对象或者资源二进制文件封装到Assetbundle中&#xff0c;提供了封装与解包的方法使用起来很便利。 二.移动平台特点 Assetbundle是可以把预制,文件以及场景都打包到Assetbundle中去的,但是在移动平台…

Ubuntu16.04菜单栏侧边栏不显示

2019独角兽企业重金招聘Python工程师标准>>> &#xff08;&#xff11;&#xff09;只有桌面上显示一些原有的文档或图片。但打开文档或者图片后也是没有窗口菜单栏&#xff0c;这样连关闭都没法点&#xff0c;快捷&#xff21;ltF4也没有反应。而且鼠标点击拖动不了…

C 语言中的 strtok 调用小技巧

1 #include <stdio.h>2 #include <string.h>3 4 char *my_strtok(char *buf, char *delims)5 {6 static int first 1;7 if(first){ //8 first 0; // 互斥操作&#xff0c;确保后面代码仅在本次调用执行9 return strtok(buf, delims); 10…

powershell连接数据库_PowerShell 连接SQL Server 数据库

PowerShell 通过ADO.NET连接SQL Server数据库&#xff0c;并执行SQL脚本。工作中整理的一小段脚本&#xff0c;后来没有用上&#xff0c;先记录在这里&#xff1a;建立数据库连接查询返回一个DataTatble对象执行一条SQL语句通过事物执行多条SQL语句## 建立数据库连接.#function…

GDB调试进阶

GDB 调试 ------------------------------------------------------------------------------- gdb 帮助文档 help -- 查看 gdb 的命令种类 help <CmdType> -- 查看 CmdType 种类的 gdb 命令 apropos <keyWord> -- 查看关键字 keyWord 的相关命令 info <keyWord…

RubyGems 库发现了后门版本的网站开发工具 bootstrap-sass

安全研究人员在官方的 RubyGems 库发现了后门版本的网站开发工具 bootstrap-sass。该工具的下载量高达 2800 万次&#xff0c;但这并不意味着下载的所有版本都存在后门&#xff0c;受影响的版本是 v3.2.0.3&#xff0c;研究人员呼吁用户尽可能快的更新&#xff0c;认为可能有数…

读大叔深入理解javascript(2)

Module模式的应用&#xff1a; var Caculator function(eqt){var box document.getElementById(eqt);return {add:function(x,y){return xy;}} }; var a new Caculator(11); a.add(1,3); // return 4 这种方式每次都需要new 一下&#xff0c;也就是说每个实例在内存里都是一…

android 无法接收广播_别告诉我你不认识Android中广播接收者(二)

前面我们了解了什么是广播接收者与广播接收者的创建&#xff0c;这一次我们要接着继续去了解广播接收者的相关知识&#xff0c;这些知识包括广播接收者的注册、自定义广播与广播的类型。当我们学习完广播接收者之后&#xff0c;该如何才能让它起到作用呢&#xff1f;还有广播接…

jQuery中$(function(){})与(function($){})(jQuery)的区别

首先&#xff0c;这两个函数都是在页面载入后执行的函数&#xff0c;其中两者的区别在于&#xff1a; 在jQuery中$(function(){})等同于jQuery(function(){})&#xff0c;另一个写法为jQuery(document).ready(function(){ })&#xff0c;在DOM加载完成之后立即执行&#xff0c;…

UITableView注意点

在iOS应用中&#xff0c;UITableView应该是使用率最高的视图之一了。iPod、时钟、日历、备忘录、Mail、天气、照片、电话、短信、 Safari、App Store、iTunes、Game Center⋯几乎所有自带的应用中都能看到它的身影&#xff0c;可见它的重要性。然而在使用第三方应用时&#xff…

083、Prometheus架构(2019-05-05 周日)

参考https://www.cnblogs.com/CloudMan6/p/7692765.htmlPrometheus 是一个非常优秀的监控工具&#xff0c;准确的说&#xff0c;应该是监控方案。Prometheus 提供了监控数据搜集、存储、处理、可视化和告警一整套的解决方案。Prometheus 重要组件的架构如下&#xff1a;Prometh…

自动获取mysql建表语句_脚本工具---自动解析mysql建表语句,生成sqlalchemy表对象声明...

常规建表语句&#xff1a;CREATE TABLE test_table (id int(11) NOT NULL,name char(64) NOT NULL,password char(64) NOT NULL,PRIMARY KEY (name,id)) ENGINEInnoDB DEFAULT CHARSETutf8 COMMENTtest;解析脚本代码&#xff1a;# coding:utf-8import redeftable_design_transf…

对云风 cstring 第二次解析

前言 从明天起 关心粮食和蔬菜 我有一所房子 面朝大海 春暖花开 本文前提条件 1.了解 posix 线程 2.了解 原子操作 3.具备简单C基础,或者 你也敲一遍. 如果上面不太清楚,你可以翻看我以前的博客,或者百度搜索. 结论 1.云风前辈的 玩具 cstring 有点坑, 内存管理很随意(也可能时…

C# 获取当前路径方法

//获取包含清单的已加载文件的路径或 UNC 位置。 public static string sApplicationPath Assembly.GetExecutingAssembly ( ).Location; //result: X:\xxx\xxx\xxx.dll (.dll文件所在的目录.dll文件名) //获取当前进程的完整路径&#xff0c;包含文件名(进程名)。 string st…

土地档案管理系统需求分析

土地档案管理系统需求分析 1 项目背景 随着国土大面积调查工作的全面展开和城镇地籍管理工作得以日趋细化&#xff0c;各种野外调查数据&#xff0c;不同比例尺图件资料急剧增加。特别是城市建设的空前发展以及土地有偿使用法规的实施&#xff0c;使得地籍变更日益频繁、地籍信…

mysql8.0 服务移除_Linux下彻底删除Mysql 8.0服务的方法

观看本文前最好有一定的Linux命令基础&#xff0c;具体为centos7.3环境中清除使用yum安装的Mysql卸载前请先关闭Mysql服务service mysql stop使用 rpm 命令的方式查看已安装的mysqlrpm -qa|grep mysql开始卸载Mysql服务使用yum安装需要先进行清除服务等yum remove mysql mysql-…

老李推荐:第14章4节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-装备ViewServer-端口转发 1...

老李推荐&#xff1a;第14章4节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-装备ViewServer-端口转发 在初始化HierarchyViewer的实例过程中&#xff0c;HierarchyViewer会调用自己的成员方法setupViewServer来把ViewServer装备好&#xff0c;那么我们这里先看下这个方法…

泛型详解 高级进阶

泛型详解 高级进阶 转载于:https://www.cnblogs.com/thiaoqueen/p/10830499.html

vim 的中文编码问题

在vim编辑的时候会出现中文编码问题&#xff0c;我们可以这样解决在/usr/share/vim/的目录下有一个vimrc文件打开这个文件&#xff0c;你可能要用sudo打开然后在最后输入这行代码保存即可&#xff1a;$> sudo vim /usr/share/vim/vimrc set fileencodingsutf-8,gb2312,gbk,g…

mysql回表_到底什么情况下mysql innodb会发生回表操作?

谢邀MySQL innodb的主键索引是簇集索引&#xff0c;也就是索引的叶子节点存的是整个单条记录的所有字段值&#xff0c;不是主键索引的就是非簇集索引&#xff0c;非簇集索引的叶子节点存的是主键字段的值。回表是什么意思&#xff1f;就是你执行一条sql语句&#xff0c;需要从两…

经验分享:CSS浮动(float,clear)通俗讲解

很早以前就接触过CSS&#xff0c;但对于浮动始终非常迷惑&#xff0c;可能是自身理解能力差&#xff0c;也可能是没能遇到一篇通俗的教程。 前些天小菜终于搞懂了浮动的基本原理&#xff0c;迫不及待的分享给大家。 写在前面的话&#xff1a; 由于CSS内容比较多&#xff0c;小菜…

前端开发学习Day27

第27天&#xff0c;我只做了一个案例。布局部分花了一整个上午&#xff0c;很乱。代码还是写的少&#xff0c;没有思路。下午好不容易做好了布局&#xff0c;写脚本的时候又被卡死&#xff0c;我现在严重怀疑自己的大脑是怎么长的……本着不抛弃不放弃的原则&#xff0c;晚上找…

对象模型创建SharePoint2010多选字段SPFieldMultiChoice

在使用页面方式创建SharePoint 2010的选项(Choice)字段时&#xff0c;选项字段的显示方式有3种&#xff1a;下拉列表、单选按钮、多选。但是如果使用对象模型创建时&#xff0c;下拉列表和单选按钮只能使用SPFieldChoice类来创建&#xff0c;而多选显示方式就要使用SPFieldMult…

docker mysql忘记密码_docker基于mysql镜像构建mysql容器忘记密码解决办法

环境&#xff1a;[rootmaster-106 ~]# cat /etc/redhat-releaseCentOS Linux release 7.6.1810 (Core)[rootmaster-106 ~]# docker --versionDocker version 19.03.13, build 4484c46d9dMySQL 5.7.31# 进入mysql容器[rootmaster-106 ~]# docker ps|grep mysql05759803adb9 mysq…

Android App优化之延长电池续航时间

禁用广播接收器 确保广播接收器在真正须要时才运行指令&#xff0c;在onResume中当中广播接收器&#xff0c;在onPause中禁用。 在manifest文件里声明广播接收器时&#xff0c;事先默认配置成禁用的 <receiver android:name".BatterReceiver" android:enabled&quo…

myeclipse中安装svn插件

1、下载最新的SVN包(我下的是1.0.6版)&#xff1a; http://subclipse.tigris.org/servlets/ProjectDocumentList?folderID2240 2、在你的磁盘上任意位置创建文件夹&#xff1a;“myplugins/svn”。名字可以任取&#xff0c;为了方便插件管理&#xff0c;建议名称为“myplugins…

字节码学院全栈学习笔记

今天正式加入字节码学院&#xff0c;努力学习Java全栈&#xff0c;争取在6个月内称为一个了解软件行业的人&#xff0c;本人在这里立铁为证&#xff1a; 搭建vue 组件化开发环境时&#xff0c;需要安装node.js step 01: nodejs 安装 sudo apt updatesudo apt install nodejsno…