CPPFormatLibary,以下简称FL,介绍:关于CPPFormatLibary

与stringstream,甚至C库的sprintf系列想比,FL在速度上都有优势,而且是在支持.net格式化风格的基础上。要实现这一点,需要多种优化结合在一起,有代码技巧方面的,也有设计策略上的。下面简要的对这些内容进行讲解:

1.  Pattern缓存

在C库函数sprintf中,比如这行代码:

  1. char szBuf[];
  2. sprintf_s(szBuf, "%d--#--%8.2f--#--%s", , -40.2f, " String ");

格式化字符串"%d--#--%8.2f--#--%s"在每次函数调用的时候,都需要分析一次,依次找出对应的格式化符,在实际开发过程中,多数情况下,格式化字符串并没有任何不同,因此这个分析属于重复分析。因此在设计FL时将这样的格式化字符串称为PatternList,并使用Hash容器对这个PatternList进行存储,在每次格式化之前,首先在容器中查找对应字符串的Pattern是否已经存在,有的话则直接使用已经分析的结果。

下面的代码是Pattern的定义,PatternList则为对应的数组:

  1. 1 /**
  2. * @brief This is the description of a Format unit
  3. * @example {0} {0:d}
  4. */
  5. template < typename TCharType >
  6. class TFormatPattern
  7. {
  8. public:
  9. typedef TCharType CharType;
  10. typedef unsigned char ByteType;
  11. typedef std::size_t SizeType;
  12.  
  13. enum EFormatFlag
  14. {
  15. FF_Raw,
  16. FF_None,
  17. FF_Decimal,
  18. FF_Exponent,
  19. FF_FixedPoint,
  20. FF_General,
  21. FF_CSV,
  22. FF_Percentage,
  23. FF_Hex
  24. };
  25.  
  26. enum EAlignFlag
  27. {
  28. AF_Right,
  29. AF_Left
  30. };
  31.  
  32. TFormatPattern() :
  33. Start((SizeType)-),
  34. Len(),
  35. Flag(FF_Raw),
  36. Align(AF_Right),
  37. Index((ByteType)-),
  38. Precision((ByteType)-),
  39. Width((ByteType)-)
  40.  
  41. {
  42. }
  43.  
  44. SizeType GetLegnth() const
  45. {
  46. return Len;
  47. }
  48.  
  49. bool IsValid() const
  50. {
  51. return Start != - && Len != - && Index >= ;
  52. }
  53.  
  54. bool HasWidth() const
  55. {
  56. return Width != (ByteType)-;
  57. }
  58.  
  59. bool HasPrecision() const
  60. {
  61. return Precision != (ByteType)-;
  62. }
  63.  
  64. public:
  65. SizeType Start;
  66. SizeType Len;
  67. EFormatFlag Flag;
  68. EAlignFlag Align;
  69.  
  70. ByteType Index;
  71. ByteType Precision;
  72. ByteType Width;
  73. };

这个Pattern就代表了分析格式化字符串的每一个单元。

  1. 1 StandardLibrary::FormatTo(str, "{0}--#--{1,8}--#--{2}", , -40.2f, " String ");

在这行代码中,PatternList一共有5个Pattern,分别是:

  1. {} 参数0
  2.  
  3. --#-- 原始类型
  4.  
  5. {,} 参数1 宽度8
  6.  
  7. --#-- 原始类型 纯字符串
  8.  
  9. {} 参数2

这样设计可以优化掉重复的字符串Parse。

2.各种类型到字符串转换的算法优化

这部分代码完全存在于文件Algorithm.hpp中,这里面包含了诸如int、double等转换为字符串的快速算法,实测性能优于sprintf和atoi之类。通过这些基础算法的优化,性能可以得到相当不错的提升。

  1. template < typename TCharType >
  2. inline void StringReverse(TCharType* Start, TCharType* End)
  3. {
  4. TCharType Aux;
  5.  
  6. while (Start < End)
  7. {
  8. Aux = *End;
  9. *End-- = *Start;
  10. *Start++ = Aux;
  11. }
  12. }
  13.  
  14. namespace Detail
  15. {
  16. const char DigitMap[] =
  17. {
  18. '', '', '', '', '', '', '',
  19. '', '', '', 'A', 'B', 'C', 'D',
  20. 'E', 'F'
  21. };
  22. }
  23.  
  24. template < typename TCharType >
  25. inline SIZE_T Int64ToString(INT64 Value, TCharType* Buf, INT Base)
  26. {
  27. assert(Base > && static_cast<SIZE_T>(Base) <= _countof(Detail::DigitMap));
  28.  
  29. TCharType* Str = Buf;
  30.  
  31. UINT64 UValue = (Value < ) ? -Value : Value;
  32.  
  33. // Conversion. Number is reversed.
  34. do
  35. {
  36. *Str++ = Detail::DigitMap[UValue%Base];
  37. } while (UValue /= Base);
  38.  
  39. if (Value < )
  40. {
  41. *Str++ = '-';
  42. }
  43.  
  44. *Str = '\0';
  45.  
  46. // Reverse string
  47. StringReverse<TCharType>(Buf, Str - );
  48.  
  49. return Str - Buf;
  50. }

上面这段代码展示的是快速整数到字符串的转换。据说基于sse指令的各种转换会更快,然而担心兼容性问题影响跨平台,我并未采用。

3. 栈容器和栈字符串

这部分代码存在于文件Utility.hpp中,这部分代码的优化原理就是在需要的动态内存并不大的时候,直接使用栈内存,当内存需求大到超过一定阀值的时候,自动申请堆内存并将栈数据转移到堆内存上。在大多数情况下,我们需要的内存都是很少,因此在绝大多数情况下,都能起到相当显著的优化效果。

  1. template <
  2. typename T,
  3. INT DefaultLength = 0xFF,
  4. INT ExtraLength =
  5. >
  6. class TAutoArray
  7. {
  8. public:
  9. typedef TAutoArray<T, DefaultLength, ExtraLength> SelfType;
  10.  
  11. enum
  12. {
  13. DEFAULT_LENGTH = DefaultLength
  14. };
  15.  
  16. class ConstIterator : Noncopyable
  17. {
  18. public:
  19. ConstIterator(const SelfType& InRef) :
  20. Ref(InRef),
  21. Index( InRef.GetLength()>?:- )
  22. {
  23. }
  24.  
  25. bool IsValid() const
  26. {
  27. return Index < Ref.GetLength();
  28. }
  29.  
  30. bool Next()
  31. {
  32. ++Index;
  33.  
  34. return IsValid();
  35. }
  36.  
  37. const T& operator *() const
  38. {
  39. const T* Ptr = Ref.GetDataPtr();
  40.  
  41. return Ptr[Index];
  42. }
  43. private:
  44. ConstIterator& operator = (const ConstIterator&);
  45. ConstIterator(ConstIterator&);
  46. protected:
  47. const SelfType& Ref;
  48. SIZE_T Index;
  49. };
  50.  
  51. TAutoArray() :
  52. Count(),
  53. AllocatedCount(),
  54. HeapValPtr(NULL)
  55. {
  56. }
  57.  
  58. ~TAutoArray()
  59. {
  60. ReleaseHeapData();
  61.  
  62. Count = ;
  63. }
  64.  
  65. TAutoArray(const SelfType& Other) :
  66. Count(Other.Count),
  67. AllocatedCount(Other.AllocatedCount),
  68. HeapValPtr(NULL)
  69. {
  70. if (Count > )
  71. {
  72. if (Other.IsDataOnStack())
  73. {
  74. Algorithm::CopyArray(Other.StackVal, Other.StackVal + Count, StackVal);
  75. }
  76. else
  77. {
  78. HeapValPtr = Allocate(AllocatedCount);
  79. Algorithm::CopyArray(Other.HeapValPtr, Other.HeapValPtr + Count, HeapValPtr);
  80. }
  81. }
  82. }
  83.  
  84. SelfType& operator = (const SelfType& Other)
  85. {
  86. if (this == &Other)
  87. {
  88. return *this;
  89. }
  90.  
  91. ReleaseHeapData();
  92.  
  93. Count = Other.Count;
  94. AllocatedCount = Other.AllocatedCount;
  95. HeapValPtr = NULL;
  96.  
  97. if (Count > )
  98. {
  99. if (Other.IsDataOnStack())
  100. {
  101. Algorithm::CopyArray(Other.StackVal, Other.StackVal + Count, StackVal);
  102. }
  103. else
  104. {
  105. HeapValPtr = Allocate(AllocatedCount);
  106. Algorithm::CopyArray(Other.HeapValPtr, Other.HeapValPtr + Count, HeapValPtr);
  107. }
  108. }
  109.  
  110. return *this;
  111. }
  112.  
  113. SelfType& TakeFrom(SelfType& Other)
  114. {
  115. if (this == &Other)
  116. {
  117. return *this;
  118. }
  119.  
  120. Count = Other.Count;
  121. AllocatedCount = Other.AllocatedCount;
  122. HeapValPtr = Other.HeapValPtr;
  123.  
  124. if (Count > && Other.IsDataOnStack())
  125. {
  126. Algorithm::MoveArray(Other.StackVal, Other.StackVal + Count, StackVal);
  127. }
  128.  
  129. Other.Count = ;
  130. Other.AllocatedCount = ;
  131. Other.HeapValPtr = NULL;
  132. }
  133.  
  134. void TakeTo(SelfType& Other)
  135. {
  136. Other.TakeFrom(*this);
  137. }
  138.  
  139. #if FL_PLATFORM_HAS_RIGHT_VALUE_REFERENCE
  140. TAutoArray( SelfType && Other ) :
  141. Count(Other.Count),
  142. AllocatedCount(Other.AllocatedCount),
  143. HeapValPtr(Other.HeapValPtr)
  144. {
  145. if (Count > && Other.IsDataOnStack())
  146. {
  147. Algorithm::MoveArray(Other.StackVal, Other.StackVal + Count, StackVal);
  148. }
  149.  
  150. Other.Count = ;
  151. Other.AllocatedCount = ;
  152. Other.HeapValPtr = NULL;
  153. }
  154.  
  155. SelfType& operator = (SelfType&& Other )
  156. {
  157. return TakeFrom(Other);
  158. }
  159. #endif
  160.  
  161. bool IsDataOnStack() const
  162. {
  163. return HeapValPtr == NULL;
  164. }
  165.  
  166. void AddItem(const T& InValue)
  167. {
  168. if (IsDataOnStack())
  169. {
  170. if (Count < DEFAULT_LENGTH)
  171. {
  172. StackVal[Count] = InValue;
  173. ++Count;
  174. }
  175. else if (Count == DEFAULT_LENGTH)
  176. {
  177. InitialMoveDataToHeap();
  178.  
  179. assert(Count < AllocatedCount);
  180.  
  181. HeapValPtr[Count] = InValue;
  182. ++Count;
  183. }
  184. else
  185. {
  186. assert(false && "internal error");
  187. }
  188. }
  189. else
  190. {
  191. if (Count < AllocatedCount)
  192. {
  193. HeapValPtr[Count] = InValue;
  194. ++Count;
  195. }
  196. else
  197. {
  198. ExpandHeapSpace();
  199.  
  200. assert(Count < AllocatedCount);
  201. HeapValPtr[Count] = InValue;
  202. ++Count;
  203. }
  204. }
  205. }
  206.  
  207. SIZE_T GetLength() const
  208. {
  209. return Count;
  210. }
  211.  
  212. SIZE_T GetAllocatedCount() const
  213. {
  214. return AllocatedCount;
  215. }
  216.  
  217. T* GetDataPtr()
  218. {
  219. return IsDataOnStack() ? StackVal : HeapValPtr;
  220. }
  221.  
  222. const T* GetDataPtr() const
  223. {
  224. return IsDataOnStack() ? StackVal : HeapValPtr;
  225. }
  226.  
  227. T* GetUnusedPtr()
  228. {
  229. return IsDataOnStack() ? StackVal + Count : HeapValPtr + Count;
  230. }
  231.  
  232. const T* GetUnusedPtr() const
  233. {
  234. return IsDataOnStack() ? StackVal + Count : HeapValPtr + Count;
  235. }
  236.  
  237. SIZE_T GetCapacity() const
  238. {
  239. return IsDataOnStack() ?
  240. DEFAULT_LENGTH - Count :
  241. AllocatedCount - Count;
  242. }
  243.  
  244. T& operator []( SIZE_T Index )
  245. {
  246. assert( Index < GetLength() );
  247.  
  248. return GetDataPtr()[Index];
  249. }
  250.  
  251. const T& operator []( SIZE_T Index ) const
  252. {
  253. assert( Index < GetLength() );
  254.  
  255. return GetDataPtr()[Index];
  256. }
  257.  
  258. protected:
  259. void InitialMoveDataToHeap()
  260. {
  261. assert(HeapValPtr == NULL);
  262.  
  263. AllocatedCount = DEFAULT_LENGTH * ;
  264.  
  265. HeapValPtr = Allocate(AllocatedCount);
  266.  
  267. #if FL_PLATFORM_HAS_RIGHT_VALUE_REFERENCE
  268. Algorithm::MoveArray(StackVal, StackVal + Count, HeapValPtr);
  269. #else
  270. Algorithm::CopyArray(StackVal, StackVal + Count, HeapValPtr);
  271. #endif
  272. }
  273.  
  274. void ExpandHeapSpace()
  275. {
  276. SIZE_T NewCount = AllocatedCount * ;
  277. assert(NewCount > AllocatedCount);
  278.  
  279. T* DataPtr = Allocate(NewCount);
  280.  
  281. assert(DataPtr);
  282.  
  283. #if FL_PLATFORM_HAS_RIGHT_VALUE_REFERENCE
  284. Algorithm::MoveArray(HeapValPtr, HeapValPtr + Count, DataPtr);
  285. #else
  286. Algorithm::CopyArray(HeapValPtr, HeapValPtr + Count, DataPtr);
  287. #endif
  288. ReleaseHeapData();
  289.  
  290. HeapValPtr = DataPtr;
  291. AllocatedCount = NewCount;
  292. }
  293.  
  294. void ReleaseHeapData()
  295. {
  296. if (HeapValPtr)
  297. {
  298. delete[] HeapValPtr;
  299. HeapValPtr = NULL;
  300. }
  301.  
  302. AllocatedCount = ;
  303. }
  304.  
  305. static T* Allocate(const SIZE_T InAllocatedCount)
  306. {
  307. // +ExtraLength this is a hack method for saving string on it.
  308. return new T[InAllocatedCount + ExtraLength];
  309. }
  310.  
  311. protected:
  312. SIZE_T Count;
  313. SIZE_T AllocatedCount;
  314.  
  315. // +ExtraLength this is a hack method for saving string on it.
  316. T StackVal[DEFAULT_LENGTH + ExtraLength];
  317.  
  318. T* HeapValPtr;
  319. };

上面这段代码展示的就是这个设想的实现。这是一个模板类,基于这个类实现了栈字符串。同时默认的PatternList也是使用这个模板来保存的,这样在节约了大量的内存分配操作之后,性能得到进一步的提升。

  1. // String Wrapper
  2. template < typename TCharType >
  3. class TAutoString :
  4. public TAutoArray< TCharType, 0xFF, >
  5. {
  6. public:
  7. typedef TAutoArray< TCharType, 0xFF, > Super;
  8. typedef Mpl::TCharTraits<TCharType> CharTraits;
  9. typedef TCharType CharType;
  10.  
  11. #if !FL_COMPILER_MSVC
  12. using Super::Count;
  13. using Super::AllocatedCount;
  14. using Super::HeapValPtr;
  15. using Super::StackVal;
  16. using Super::Allocate;
  17. using Super::IsDataOnStack;
  18. using Super::DEFAULT_LENGTH;
  19. using Super::GetDataPtr;
  20. using Super::ReleaseHeapData;
  21. #endif
  22.  
  23. TAutoString()
  24. {
  25. }
  26.  
  27. TAutoString(const CharType* pszStr)
  28. {
  29. if (pszStr)
  30. {
  31. const SIZE_T Length = CharTraits::length(pszStr);
  32.  
  33. Count = Length;
  34.  
  35. if (Length <= DEFAULT_LENGTH)
  36. {
  37. CharTraits::copy(pszStr, pszStr + Length, StackVal);
  38. StackVal[Count] = ;
  39. }
  40. else
  41. {
  42. HeapValPtr = Allocate(Length);
  43. CharTraits::copy(pszStr, pszStr + Length, HeapValPtr);
  44. HeapValPtr[Count] = ;
  45. }
  46. }
  47. }
  48.  
  49. void AddChar(CharType InValue)
  50. {
  51. AddItem(InValue);
  52.  
  53. if (IsDataOnStack())
  54. {
  55. StackVal[Count] = ;
  56. }
  57. else
  58. {
  59. HeapValPtr[Count] = ;
  60. }
  61. }
  62.  
  63. void AddStr(const CharType* pszStart, const CharType* pszEnd = NULL)
  64. {
  65. const SIZE_T Length = pszEnd ? pszEnd - pszStart : CharTraits::length(pszStart);
  66.  
  67. if (IsDataOnStack())
  68. {
  69. if (Count + Length <= DEFAULT_LENGTH)
  70. {
  71. CharTraits::copy(StackVal+Count, pszStart, Length);
  72. Count += Length;
  73.  
  74. StackVal[Count] = ;
  75. }
  76. else
  77. {
  78. assert(!HeapValPtr);
  79.  
  80. AllocatedCount = static_cast<SIZE_T>((Count + Length)*1.5f);
  81. HeapValPtr = Allocate(AllocatedCount);
  82. assert(HeapValPtr);
  83.  
  84. if (Count > )
  85. {
  86. CharTraits::copy(HeapValPtr, StackVal, Count);
  87. }
  88.  
  89. CharTraits::copy(HeapValPtr+Count, pszStart, Length);
  90.  
  91. Count += Length;
  92.  
  93. HeapValPtr[Count] = ;
  94. }
  95. }
  96. else
  97. {
  98. if (Count + Length <= AllocatedCount)
  99. {
  100. CharTraits::copy(HeapValPtr+Count, pszStart, Length);
  101. Count += Length;
  102.  
  103. HeapValPtr[Count] = ;
  104. }
  105. else
  106. {
  107. SIZE_T NewCount = static_cast<SIZE_T>((Count + Length)*1.5f);
  108.  
  109. CharType* DataPtr = Allocate(NewCount);
  110.  
  111. if (Count > )
  112. {
  113. CharTraits::copy(DataPtr, HeapValPtr, Count);
  114. }
  115.  
  116. ReleaseHeapData();
  117.  
  118. CharTraits::copy(DataPtr, pszStart, Length);
  119.  
  120. Count += Length;
  121.  
  122. AllocatedCount = NewCount;
  123. HeapValPtr = DataPtr;
  124.  
  125. HeapValPtr[Count] = ;
  126. }
  127. }
  128. }
  129.  
  130. const TCharType* CStr() const
  131. {
  132. return GetDataPtr();
  133. }
  134.  
  135. // is is a internal function
  136. //
  137. void InjectAdd(SIZE_T InCount)
  138. {
  139. Count += InCount;
  140.  
  141. assert(IsDataOnStack() ? (Count <= DEFAULT_LENGTH) : (Count < AllocatedCount));
  142. }
  143.  
  144. protected:
  145. void AddItem(const TCharType& InValue)
  146. {
  147. Super::AddItem(InValue);
  148. }
  149. };

上面展示的是基于栈内存容器实现的栈字符串,在大多数情况下,我们格式化字符串时都采用栈字符串来保存结果,这样可以显著的提升性能。

同时栈容器和栈字符串,都特别适合于当临时容器和临时字符串,因为多数情况下它们都优化掉了可能需要动态内存分配的操作。所以它们的使用并不局限于这一个小地方。

4. 基于C++ 11的优化

除了引入了C++ 11的容器unordered_map之外,还引入了右值引用等新内容,在某些情况下,可以带来一定的性能提升。

  1. #if FL_PLATFORM_HAS_RIGHT_VALUE_REFERENCE
  2. TAutoArray( SelfType && Other ) :
  3. Count(Other.Count),
  4. AllocatedCount(Other.AllocatedCount),
  5. HeapValPtr(Other.HeapValPtr)
  6. {
  7. if (Count > && Other.IsDataOnStack())
  8. {
  9. Algorithm::MoveArray(Other.StackVal, Other.StackVal + Count, StackVal);
  10. }
  11.  
  12. Other.Count = ;
  13. Other.AllocatedCount = ;
  14. Other.HeapValPtr = NULL;
  15. }
  16.  
  17. SelfType& operator = (SelfType&& Other )
  18. {
  19. return TakeFrom(Other);
  20. }
  21. #endif

上面展示的是基于右值引用的优化。

除此之外还是用了线程局部存储(TLS),这依赖于编译器是否支持。前面提到了我们采用Hash容器来存储Pattern缓存,然而在单线程的时候自然无需多余考虑,当需要支持多线程时,则全局唯一的Hash容器的访问都需要加锁,而加锁是有性能开销的。幸好C++ 11带来了内置的TLS支持,其结果就是每个线程会独立保存一份这样的Pattern缓存,因此无需对其访问加锁,这样无疑效率会更高。缺陷则是会损失部分内存。所有的这些都可以通过预先的宏定义来进行开关,使用者可以自行决定使用TLS还是Lock,或者不支持多线程。

  1. template < typename TPolicy >
  2. class TGlobalPatternStorage :
  3. public TPatternStorage<TPolicy>
  4. {
  5. public:
  6. static TGlobalPatternStorage* GetStorage()
  7. {
  8. #if FL_WITH_THREAD_LOCAL
  9. struct ManagedStorage
  10. {
  11. typedef Utility::TScopedLocker<System::CriticalSection> LockerType;
  12.  
  13. System::CriticalSection ManagedCS;
  14. Utility::TAutoArray<TGlobalPatternStorage*> Storages;
  15.  
  16. ~ManagedStorage()
  17. {
  18. LockerType Locker(ManagedCS);
  19.  
  20. for( SIZE_T i=; i<Storages.GetLength(); ++i )
  21. {
  22. delete Storages[i];
  23. }
  24. }
  25.  
  26. void AddStorage( TGlobalPatternStorage* Storage )
  27. {
  28. assert(Storage);
  29.  
  30. LockerType Locker(ManagedCS);
  31.  
  32. Storages.AddItem(Storage);
  33. }
  34. };
  35.  
  36. static ManagedStorage StaticManager;
  37.  
  38. static FL_THREAD_LOCAL TGlobalPatternStorage* StaticStorage = NULL;
  39.  
  40. if( !StaticStorage )
  41. {
  42. StaticStorage = new TGlobalPatternStorage();
  43.  
  44. StaticManager.AddStorage(StaticStorage);
  45. }
  46.  
  47. return StaticStorage;
  48. #else
  49. static TGlobalPatternStorage StaticStorage;
  50. return &StaticStorage;
  51. #endif
  52. }
  53. };

如上所示为项目中使用TLS的代码。

总结

在将这一系列的优化结合起来之后,可以使得FL的整体效率处于较高水平,不低于C库函数,同时还具备其它格式化库不具备的功能,对于代码安全性等各方面的增强,都有帮助。下面是Test.cpp的测试结果,FL代表的是使用FL库的耗时,CL代表的C库的耗时,同时此测试模拟了多线程环境。

Windows Visual Studio 2013 Release下的输出:

  1. 0x64
  2. Test20, -10.0050, X , X
  3. 0x64
  4. Test20, -10.0050, X , X
  5. 1920 FLElapse:0.0762746
  6. 1920 CLElapse:0.269722
  7. 1636 FLElapse:0.0756153
  8. 7732 FLElapse:0.0766446
  9. 7956 FLElapse:0.0762051
  10. 7956 CLElapse:0.285714
  11. 1636 CLElapse:0.288648
  12. 7732 CLElapse:0.289193

Mac Xcode Release:

  1. 99
  2. Test20, -10.0050, X , X
  3. 18446744073709551615 FLElapse:0.0901681
  4. 18446744073709551615 CLElapse:0.19329
  5. 18446744073709551615 FLElapse:0.147378
  6. 18446744073709551615 FLElapse:0.150375
  7. 18446744073709551615 FLElapse:0.153342
  8. 18446744073709551615 CLElapse:0.303508
  9. 18446744073709551615 CLElapse:0.308418
  10. 18446744073709551615 CLElapse:0.307407

这并非完全的测试,更多的测试需要在实际使用过程中来验证。

CPPFormatLibary提升效率的优化原理的更多相关文章

  1. paip.提升效率--数据绑定到table原理和流程Angular js jquery实现

    paip.提升效率--数据绑定到table原理和流程Angular js  jquery实现 html #--keyword 1 #---原理和流程 1 #----jq实现的代码 1 #-----An ...

  2. MySQL Optimization 优化原理

    MySQL Optimization 优化原理 MySQL逻辑架构 如果能在头脑中构建一幅MySQL各组件之间如何协同工作的架构图,有助于深入理解MySQL服务器.下图展示了MySQL的逻辑架构图. ...

  3. MySQL架构及优化原理

    1 MySQL架构原理 1.1 MySQL架构原理参看下述链接: https://blog.csdn.net/hguisu/article/details/7106342 1.2 MySQL优化详解参 ...

  4. atitit groovy 总结java 提升效率

    atitit groovy 总结java 提升效率 #---环境配置 1 #------安装麻烦的 2 三.创建groovy项目 2 3.  添加 Groovy 类 2 4.  编译运行groovy类 ...

  5. paip.提升效率--僵尸代码的迷思

    paip.提升效率--僵尸代码的迷思 僵尸代码是指你的代码库里被注释掉的那部分代码, 很少去使用它,就像僵尸一样, 看雷kill-the-zombies-in-your-code ========== ...

  6. mysql数据库的优化和查询效率的优化

    一.数据库的优化 1.优化索引.SQL 语句.分析慢查询: 2.设计表的时候严格根据数据库的设计范式来设计数据库: 3.使用缓存,把经常访问到的数据而且不需要经常变化的数据放在缓存中,能节约磁盘IO: ...

  7. 纯前端表格控件SpreadJS以专注业务、提升效率赢得用户与市场

    提起华为2012实验室,你可能有点陌生. 但你一定还对前段时间华为的那封<海思总裁致员工的一封信>记忆犹新,就在那篇饱含深情的信中,我们知道了华为为确保公司大部分产品的战略安全和连续供应, ...

  8. deeplearning算法优化原理

    deeplearning算法优化原理目录· 量化原理介绍 · 剪裁原理介绍 · 蒸馏原理介绍 · 轻量级模型结构搜索原理介绍 1. Quantization Aware Training量化介绍1.1 ...

  9. sql语句优化原理

    前言 网上有很多关于sql语句优化的文章,我这里想说下为什么这样...写sql语句,能够提高查询的效率. 1 sql语句优化原理 要想写出好的sql,就要学会用数据库的方式来思考如何执行sql,那么什 ...

随机推荐

  1. MVC

    PureMVC--一款多平台MVC框架 http://www.jianshu.com/p/47deaced9eb3 MVC,MVP 和 MVVM 的图示 http://www.ruanyifeng.c ...

  2. Git 总结

    详情请参考:https://git-scm.com/book/zh/v2 注意事项:#1. 多提交(相当于多保存,多^S): 在Git中任何已提交的东西几乎总是可以恢复的. 甚至那些被删除的分支中的提 ...

  3. 每天写点shell--命令行参数

    1.读取参数:位置参数变量是标准的数字: $0是程序名, $1是第一个参数, $2是第二个参数... #!/bin/bash # using one command line parameter fa ...

  4. Java文件操作

    1.通过File类中的createNewFile()创建一个新的文件 /**     * 测试创建文件     * @throws IOException     */    @Test    pub ...

  5. vi 的使用

    Vi 分三种模式:一般模式,编辑模式,和命令模式 一般模式: 光标移动,搜索与替换,删除,复制,粘贴 编辑模式:插入或者替换文本 命令模式:读取.保存文件 一般模式 光标移动: h(左), j(下), ...

  6. Matlab与Windows桌面提醒

    最近在实验室用Matlab做实验,一次训练下来最少得也得5到10分钟吧.在Matlab运行的过程中,又不太好去做别的事情,因为5到10分钟的时间实在有点短.但是,眼睁睁看着代码的运行的话,5分钟又实在 ...

  7. 使用Docker Mysql 5.7

    Mysql已经提供了Docker image,可以很方便开启一个mysql服务器.官方介绍了两种连接方式, 在其他App Docker 容器中通过--link访问Mysql服务端容器 启动另外一个My ...

  8. Ajax商品分类三级联动实现

    思路分析: 效果:当页面加载时,利用ajax异步向后台请求数据,加载一级商品类别,当选择一级商品时加载二级商品,选择二级商品加载三级商品. 实现: 1.当拿到数据后加载pid为0的商品,并动态创建op ...

  9. Angular2 依赖注入

    1. 使用DI 依赖注入是一个很重要的程序设计模式. Angular 有自己的依赖注入框架,离开了它,我们几乎没法构建 Angular 应用.它使用得非常广泛,以至于几乎每个人都会把它简称为 DI. ...

  10. android 6.0 高通平台sensor 工作机制及流程(原创)

    最近工作上有碰到sensor的相关问题,正好分析下其流程作个笔记. 这个笔记分三个部分: sensor硬件和驱动的工作机制 sensor 上层app如何使用 从驱动到上层app这中间的流程是如何 Se ...