කණ්ඩායම් විමසුම් සැකසීමේ ගැටළු සහ ඒවාට විසඳුම් (1 කොටස)

කණ්ඩායම් විමසුම් සැකසීමේ ගැටළු සහ ඒවාට විසඳුම් (1 කොටස)සියලුම නවීන මෘදුකාංග නිෂ්පාදන පාහේ සේවා කිහිපයකින් සමන්විත වේ. බොහෝ විට, අන්තර් සේවා නාලිකාවල දිගු ප්‍රතිචාර කාලය කාර්ය සාධන ගැටළු වල මූලාශ්‍රයක් බවට පත්වේ. මෙම ආකාරයේ ගැටලුවකට සම්මත විසඳුම වන්නේ බහු අන්තර් සේවා ඉල්ලීම් එක් පැකේජයකට ඇසුරුම් කිරීමයි, එය batching ලෙස හැඳින්වේ.

ඔබ කණ්ඩායම් සැකසුම් භාවිතා කරන්නේ නම්, කාර්ය සාධනය හෝ කේත පැහැදිලිකම අනුව ප්‍රතිඵල ගැන ඔබ සතුටු නොවිය හැක. මෙම ක්‍රමය ඔබ සිතන තරම් අමතන්නාට පහසු නැත. විවිධ අරමුණු සඳහා සහ විවිධ අවස්ථාවන්හිදී, විසඳුම් බෙහෙවින් වෙනස් විය හැකිය. නිශ්චිත උදාහරණ භාවිතා කරමින්, මම ප්රවේශයන් කිහිපයක වාසි සහ අවාසි පෙන්වමි.

නිදර්ශන ව්යාපෘතිය

පැහැදිලිකම සඳහා, මම දැනට වැඩ කරන යෙදුමේ එක් සේවාවක උදාහරණයක් බලමු.

උදාහරණ සඳහා වේදිකා තෝරාගැනීමේ පැහැදිලි කිරීමදුර්වල කාර්ය සාධනය පිළිබඳ ගැටළුව තරමක් පොදු වන අතර කිසිදු විශේෂිත භාෂාවකට හෝ වේදිකාවකට බලපාන්නේ නැත. මෙම ලිපිය ගැටළු සහ විසඳුම් විදහා දැක්වීමට Spring + Kotlin කේත උදාහරණ භාවිතා කරනු ඇත. Kotlin ජාවා සහ C# සංවර්ධකයින්ට සමානව තේරුම් ගත හැකි (හෝ නොතේරෙන) වේ, ඊට අමතරව, කේතය ජාවා වලට වඩා සංයුක්ත සහ තේරුම් ගත හැකිය. පිරිසිදු ජාවා සංවර්ධකයින්ට තේරුම් ගැනීමට පහසු කිරීම සඳහා, මම කොට්ලින්ගේ කළු මැජික් මග හැර සුදු මැජික් පමණක් භාවිතා කරමි (ලොම්බොක්හි ආත්මය තුළ). දිගු කිරීමේ ක්‍රම කිහිපයක් ඇත, නමුත් ඒවා ඇත්ත වශයෙන්ම සියලුම ජාවා ක්‍රමලේඛකයින්ට ස්ථිතික ක්‍රම ලෙස හුරුපුරුදුය, එබැවින් මෙය කුඩා සීනි වර්ගයක් වන අතර එය පිඟානේ රසය නරක් නොවනු ඇත.
ලේඛන අනුමත කිරීමේ සේවාවක් ඇත. යමෙක් ලේඛනයක් සාදා එය සාකච්ඡාව සඳහා ඉදිරිපත් කරයි, එම කාලය තුළ සංස්කරණයන් සිදු කරනු ලබන අතර අවසානයේ ලේඛනය එකඟ වේ. අනුමත කිරීමේ සේවාවම ලේඛන ගැන කිසිවක් නොදනී: එය අපි මෙහි සලකා නොබලන කුඩා අමතර කාර්යයන් සහිත අනුමත කරන්නන්ගේ කතාබස් පමණි.

එබැවින්, එක් එක් ඒවායේ පූර්ව නිශ්චිත සහභාගිවන්නන් සමඟ කතාබස් කාමර (ලේඛනවලට අනුරූප) ඇත. සාමාන්‍ය කතාබස් වලදී මෙන්, පණිවිඩවල පෙළ සහ ගොනු අඩංගු වන අතර පිළිතුරු හෝ යොමු කිරීම් විය හැකිය:

data class ChatMessage(
  // nullable так как появляется только после persist
  val id: Long? = null,
  /** Ссылка на автора */
  val author: UserReference,
  /** Сообщение */
  val message: String,
  /** Ссылки на аттачи */
  // из-за особенностей связки JPA+СУБД проще поддерживать и null, и пустые списки
  val files: List<FileReference>? = null,
  /** Если является ответом, то здесь будет оригинал */
  val replyTo: ChatMessage? = null,
  /** Если является пересылкой, то здесь будет оригинал */
  val forwardFrom: ChatMessage? = null
)

ගොනු සහ පරිශීලක සබැඳි වෙනත් වසම් වෙත සබැඳි වේ. මෙන්න අපි ජීවත් වෙන්නේ මෙහෙමයි.

typealias FileReference Long
typealias UserReference Long

පරිශීලක දත්ත Keycloak හි ගබඩා කර ඇති අතර REST හරහා ලබා ගනී. ලිපිගොනු සඳහාද එය එසේම වේ: ගොනු සහ ඒවා පිළිබඳ තොරතුරු වෙනම ගොනු ගබඩා කිරීමේ සේවාවක ජීවත් වේ.

මෙම සේවාවන් සඳහා සියලුම ඇමතුම් වේ බර ඉල්ලීම්. මෙයින් අදහස් කරන්නේ මෙම ඉල්ලීම් ප්‍රවාහනය කිරීමේ පොදු කාර්ය තෙවන පාර්ශවීය සේවාවක් මඟින් ඒවා සැකසීමට ගතවන කාලයට වඩා බෙහෙවින් වැඩි බවයි. අපගේ පරීක්ෂණ බංකුවල, එවැනි සේවාවන් සඳහා සාමාන්‍ය ඇමතුම් කාලය 100 ms වේ, එබැවින් අපි අනාගතයේදී මෙම අංක භාවිතා කරන්නෙමු.

අවශ්‍ය සියලුම තොරතුරු සහිත අවසාන N පණිවිඩ ලැබීමට අපි සරල REST පාලකයක් සෑදිය යුතුය. එනම්, ඉදිරිපස ඇති පණිවිඩ ආකෘතිය පාහේ සමාන වන අතර සියලු දත්ත යැවීමට අවශ්ය බව අපි විශ්වාස කරමු. ඉදිරිපස ආකෘතිය අතර වෙනස නම්, ගොනුව සහ පරිශීලකයා සබැඳි බවට පත් කිරීම සඳහා තරමක් විකේතනය කළ ආකාරයෙන් ඉදිරිපත් කළ යුතු බවයි:

/** В таком виде отдаются ссылки на сущности для фронта */
data class ReferenceUI(
  /** Идентификатор для url */
  val ref: String,
  /** Видимое пользователю название ссылки */
  val name: String
)
data class ChatMessageUI(
  val id: Long,
  /** Ссылка на автора */
  val author: ReferenceUI,
  /** Сообщение */
  val message: String,
  /** Ссылки на аттачи */
  val files: List<ReferenceUI>,
  /** Если являтся ответом, то здесь будет оригинал */
  val replyTo: ChatMessageUI? = null,
  /** Если являтся пересылкой, то здесь будет оригинал */
  val forwardFrom: ChatMessageUI? = null
)

අපි පහත සඳහන් දෑ ක්‍රියාත්මක කළ යුතුයි.

interface ChatRestApi {
  fun getLast(nInt): List<ChatMessageUI>
}

UI postfix යන්නෙන් අදහස් කරන්නේ ඉදිරිපස සඳහා DTO මාදිලි, එනම් REST හරහා අප සේවය කළ යුතු දේයි.

මෙහි ඇති පුදුමයට කරුණ නම් අප කිසිදු චැට් හැඳුනුම්පතක් ලබා නොදීම සහ ChatMessage/ChatMessageUI ආකෘතියට පවා එකක් නොමැති වීමයි. මම මෙය හිතාමතා කළේ උදාහරණවල කේතය අවුල් නොකිරීමට (කතාබස් හුදකලා වී ඇත, එබැවින් අපට ඇත්තේ එකක් පමණක් යැයි උපකල්පනය කළ හැකිය).

දාර්ශනික අපගමනයChatMessageUI පන්තිය සහ ChatRestApi.getLast ක්‍රමය යන දෙකම එය ඇණවුම් කළ කට්ටලයක් වන විට ලැයිස්තු දත්ත වර්ගය භාවිතා කරයි. මෙය JDK හි නරක ය, එබැවින් අතුරුමුහුණත් මට්ටමේ මූලද්‍රව්‍ය අනුපිළිවෙල ප්‍රකාශ කිරීම (එකතු කිරීමේදී සහ ඉවත් කිරීමේදී අනුපිළිවෙල ආරක්ෂා කිරීම) ක්‍රියා නොකරනු ඇත. එබැවින් ඇණවුම් කළ කට්ටලයක් අවශ්‍ය වන අවස්ථා වලදී List එකක් භාවිතා කිරීම සාමාන්‍ය සිරිත වී ඇත (LinkedHashSet ද ඇත, නමුත් මෙය අතුරු මුහුණතක් නොවේ).
වැදගත් සීමාව: පිළිතුරු හෝ මාරුවීම් වල දිගු දාමයක් නොමැති බව අපි උපකල්පනය කරමු. එනම්, ඒවා පවතී, නමුත් ඒවායේ දිග පණිවිඩ තුනක් නොඉක්මවයි. සම්පූර්ණ පණිවිඩ දාමය ඉදිරිපස කොටස වෙත සම්ප්‍රේෂණය කළ යුතුය.

බාහිර සේවා වලින් දත්ත ලබා ගැනීමට පහත API ඇත:

interface ChatMessageRepository {
  fun findLast(nInt): List<ChatMessage>
}
data class FileHeadRemote(
  val id: FileReference,
  val name: String
)
interface FileRemoteApi {
  fun getHeadById(idFileReference): FileHeadRemote
  fun getHeadsByIds(idSet<FileReference>): Set<FileHeadRemote>
  fun getHeadsByIds(idList<FileReference>): List<FileHeadRemote>
  fun getHeadsByChat(): List<FileHeadRemote>
}
data class UserRemote(
  val id: UserReference,
  val name: String
)
interface UserRemoteApi {
  fun getUserById(idUserReference): UserRemote
  fun getUsersByIds(idSet<UserReference>): Set<UserRemote>
  fun getUsersByIds(idList<UserReference>): List<UserRemote>
}

බාහිර සේවාවන් මුලින් කණ්ඩායම් සැකසීම සඳහා සපයනු ලබන අතර, අනුවාද දෙකෙහිම: Set (මූලද්‍රව්‍ය අනුපිළිවෙල ආරක්ෂා නොකර, අද්විතීය යතුරු සමඟ) සහ ලැයිස්තුව හරහා (අනුපිටපත් තිබිය හැකිය - ඇණවුම සංරක්ෂණය කර ඇත).

සරල ක්රියාත්මක කිරීම්

බොළඳ ක්රියාත්මක කිරීම

අපගේ REST පාලකයේ පළමු බොළඳ ක්‍රියාත්මක කිරීම බොහෝ අවස්ථාවලදී මේ වගේ දෙයක් පෙනෙනු ඇත:

class ChatRestController(
  private val messageRepository: ChatMessageRepository,
  private val userRepository: UserRemoteApi,
  private val fileRepository: FileRemoteApi
) : ChatRestApi {
  override fun getLast(nInt) =
    messageRepository.findLast(n)
      .map it.toFrontModel() }
  
  private fun ChatMessage.toFrontModel(): ChatMessageUI =
    ChatMessageUI(
      id = id ?: throw IllegalStateException("$this must be persisted"),
      author = userRepository.getUserById(author).toFrontReference(),
      message = message,
      files = files?.let files ->
        fileRepository.getHeadsByIds(files)
          .map it.toFrontReference() }
      } ?: listOf(),
      forwardFrom = forwardFrom?.toFrontModel(),
      replyTo = replyTo?.toFrontModel()
    )
}

සෑම දෙයක්ම ඉතා පැහැදිලිය, මෙය විශාල ප්ලස් එකක්.

අපි කණ්ඩායම් සැකසීම භාවිතා කරන අතර කණ්ඩායම් වශයෙන් බාහිර සේවාවකින් දත්ත ලබා ගනිමු. නමුත් අපේ ඵලදායිතාවයට මොකද වෙන්නේ?

සෑම පණිවිඩයක් සඳහාම, කර්තෘ ක්ෂේත්‍රයේ දත්ත ලබා ගැනීමට UserRemoteApi වෙත එක් ඇමතුමක් ද අමුණා ඇති සියලුම ගොනු ලබා ගැනීමට FileRemoteApi වෙත එක් ඇමතුමක් ද කරනු ලැබේ. එය එය බව පෙනේ. අපි කියමු ChatMessage සඳහා වන forwardFrom සහ replyTo යන ක්ෂේත්‍ර මේ සඳහා අනවශ්‍ය ඇමතුම් අවශ්‍ය නොවන ආකාරයට ලබා ගන්නා බව. නමුත් ඒවා ChatMessageUI බවට පත් කිරීම පුනරාවර්තනය වීමට තුඩු දෙනු ඇත, එනම් ඇමතුම් කවුන්ටර සැලකිය යුතු ලෙස වැඩි විය හැක. අප කලින් සඳහන් කළ පරිදි, අපට කූඩු ගොඩක් නොමැති බවත්, දාමය පණිවිඩ තුනකට සීමා වී ඇති බවත් උපකල්පනය කරමු.

එහි ප්‍රතිඵලයක් වශයෙන්, අපට එක් පණිවිඩයකට බාහිර සේවාවන් වෙත ඇමතුම් දෙකේ සිට හය දක්වා සහ සම්පූර්ණ පණිවිඩ පැකේජය සඳහා එක් JPA ඇමතුමක් ලැබෙනු ඇත. මුළු ඇමතුම් ගණන 2*N+1 සිට 6*N+1 දක්වා වෙනස් වේ. සැබෑ ඒකකවල මෙය කොපමණ වේද? අපි හිතමු පේජ් එකක් රෙන්ඩර් කරන්න මැසේජ් 20ක් යනවා කියලා. ඒවා ලැබීමට තත්පර 4 සිට 10 දක්වා ගත වේ. භයානකයි! මම එය 500 ms ඇතුළත තබා ගැනීමට කැමතියි. තවද ඔවුන් ඉදිරිපස කෙළවරේ බාධාවකින් තොරව අනුචලනය කිරීමට සිහින මැවූ බැවින්, මෙම අන්ත ලක්ෂ්‍යය සඳහා කාර්ය සාධන අවශ්‍යතා දෙගුණ කළ හැකිය.

වාසි:

  1. කේතය සංක්ෂිප්ත සහ ස්වයං-ලේඛනගත වේ (සහාය කණ්ඩායමක සිහිනය).
  2. කේතය සරලයි, එබැවින් පාදයට වෙඩි තැබීමට කිසිදු අවස්ථාවක් නොමැත.
  3. කණ්ඩායම් සැකසීම පිටසක්වල දෙයක් මෙන් නොපෙනෙන අතර තර්කනයට ඓන්ද්‍රීයව ඒකාබද්ධ වේ.
  4. තාර්කික වෙනස්කම් පහසුවෙන් සිදු කරනු ලබන අතර දේශීය වනු ඇත.

අඩු:

ඉතා කුඩා පැකට් නිසා බිහිසුණු කාර්ය සාධනය.

මෙම ප්රවේශය සරල සේවා හෝ මූලාකෘති තුළ බොහෝ විට දැකිය හැකිය. වෙනස්කම් සිදු කිරීමේ වේගය වැදගත් නම්, පද්ධතිය සංකීර්ණ කිරීම කිසිසේත්ම වටින්නේ නැත. ඒ අතරම, අපගේ ඉතා සරල සේවාව සඳහා කාර්ය සාධනය භයානක ය, එබැවින් මෙම ප්රවේශයේ යෙදීමේ විෂය පථය ඉතා පටු ය.

Naive සමාන්තර සැකසුම්

ඔබට සියලුම පණිවිඩ සමාන්තරව සැකසීම ආරම්භ කළ හැකිය - පණිවිඩ ගණන අනුව රේඛීය වැඩිවීමෙන් මිදීමට මෙය ඔබට ඉඩ සලසයි. මෙය විශේෂයෙන් හොඳ මාර්ගයක් නොවේ, මන්ද එය බාහිර සේවයේ විශාල උච්ච බරක් ඇති කරයි.

සමාන්තර සැකසුම් ක්රියාත්මක කිරීම ඉතා සරල ය:

override fun getLast(nInt) =
  messageRepository.findLast(n).parallelStream()
    .map it.toFrontModel() }
    .collect(toList())

සමාන්තර පණිවිඩ සැකසීම භාවිතා කරමින්, අපි ඉතා මැනවින් 300-700 ms ලබා ගනිමු, එය බොළඳ ක්‍රියාත්මක කිරීමකට වඩා හොඳ නමුත් තවමත් ප්‍රමාණවත් තරම් වේගවත් නොවේ.

මෙම ප්‍රවේශය සමඟින්, userRepository සහ fileRepository වෙත ඉල්ලීම් සමමුහුර්තව ක්‍රියාත්මක වනු ඇත, එය එතරම් කාර්යක්ෂම නොවේ. මෙය නිවැරදි කිරීම සඳහා, ඔබට ඇමතුම් තර්කනය බොහෝ සෙයින් වෙනස් කිරීමට සිදුවනු ඇත. උදාහරණයක් ලෙස, CompletionStage හරහා (completableFuture):

private fun ChatMessage.toFrontModel(): ChatMessageUI =
  CompletableFuture.supplyAsync {
    userRepository.getUserById(author).toFrontReference()
  }.thenCombine(
    files?.let {
      CompletableFuture.supplyAsync {
        fileRepository.getHeadsByIds(files).map it.toFrontReference() }
      }
    } ?: CompletableFuture.completedFuture(listOf())
  ) authorfiles ->
    ChatMessageUI(
      id = id ?: throw IllegalStateException("$this must be persisted"),
      author = author,
      message = message,
      files = files,
      forwardFrom = forwardFrom?.toFrontModel(),
      replyTo = replyTo?.toFrontModel()
    )
  }.get()!!

මුලදී සරල සිතියම්කරණ කේතය අඩුවෙන් තේරුම් ගත හැකි වී ඇති බව පෙනේ. මෙයට හේතුව අපට බාහිර සේවා සඳහා වන ඇමතුම් ප්‍රතිඵල භාවිතා කරන ස්ථානයෙන් වෙන් කිරීමට සිදු වූ බැවිනි. මෙයම නරක නැත. නමුත් ඇමතුම් ඒකාබද්ධ කිරීම ඉතා අලංකාර පෙනුමක් නැති අතර සාමාන්ය ප්රතික්රියාශීලී "නූඩ්ල්" සමාන වේ.

ඔබ coroutines භාවිතා කරන්නේ නම්, සෑම දෙයක්ම වඩා විනීත ලෙස පෙනෙනු ඇත:

private fun ChatMessage.toFrontModel(): ChatMessageUI =
  join(
    userRepository.getUserById(author).toFrontReference() },
    files?.let fileRepository.getHeadsByIds(files)
      .map it.toFrontReference() } } ?: listOf() }
  ).let (author, files) ->
    ChatMessageUI(
      id = id ?: throw IllegalStateException("$this must be persisted"),
      author = author,
      message = message,
      files = files,
      forwardFrom = forwardFrom?.toFrontModel(),
      replyTo = replyTo?.toFrontModel()
    )
  }

කොහේද:

fun <ABjoin(a: () -> Ab: () -> B) =
  runBlocking(IO{
    awaitAll(async a() }async b() })
  }.let {
    it[0as to it[1as B
  }

න්‍යායාත්මකව, එවැනි සමාන්තර සැකසුම් භාවිතා කරමින්, අපට දැනටමත් අපගේ අපේක්ෂාවන්ට සමීප වන 200-400 ms ලැබෙනු ඇත.

අවාසනාවකට මෙන්, එවැනි හොඳ සමාන්තරකරණයක් නොපවතින අතර ගෙවිය යුතු මිල තරමක් කුරිරු ය: එකවර වැඩ කරන පරිශීලකයින් කිහිප දෙනෙකු පමණක් සමඟ, සේවාවන් මත ඉල්ලීම් විශාල ප්‍රමාණයක් වැටෙනු ඇත, එය කෙසේ හෝ සමාන්තරව ක්‍රියාත්මක නොවනු ඇත, එබැවින් අපි අපගේ දුක්ඛිත තත්පර 4 වෙත නැවත පැමිණෙනු ඇත.

එවැනි සේවාවක් භාවිතා කරන විට මගේ ප්රතිඵලය පණිවිඩ 1300 ක් සැකසීම සඳහා 1700-20 ms වේ. මෙය පළමු ක්රියාත්මක කිරීමට වඩා වේගවත් වේ, නමුත් තවමත් ගැටළුව විසඳන්නේ නැත.

සමාන්තර විමසුම්වල විකල්ප භාවිතයන්තෙවන පාර්ශවීය සේවාවන් කණ්ඩායම් සැකසුම් ලබා නොදෙන්නේ නම් කුමක් කළ යුතුද? උදාහරණයක් ලෙස, ඔබට අතුරුමුහුණත් ක්‍රම තුළ කණ්ඩායම් සැකසුම් ක්‍රියාත්මක කිරීමේ හිඟය සැඟවිය හැක:

interface UserRemoteApi {
  fun getUserById(idUserReference): UserRemote
  fun getUsersByIds(idSet<UserReference>): Set<UserRemote> =
    id.parallelStream()
      .map getUserById(it}.collect(toSet())
  fun getUsersByIds(idList<UserReference>): List<UserRemote> =
    id.parallelStream()
      .map getUserById(it}.collect(toList())
}

ඔබ අනාගත අනුවාද වල කණ්ඩායම් සැකසුම් දැකීමට බලාපොරොත්තු වන්නේ නම් මෙය අර්ථවත් කරයි.
වාසි:

  1. පණිවිඩ පදනම් වූ සමාන්තර සැකසුම් පහසුවෙන් ක්‍රියාත්මක කරන්න.
  2. හොඳ පරිමාණය.

එය:

  1. සමාන්තරව විවිධ සේවාවන් වෙත ඉල්ලීම් සැකසීමේදී දත්ත ලබා ගැනීම එහි සැකසීමෙන් වෙන් කිරීමේ අවශ්යතාව.
  2. තෙවන පාර්ශවීය සේවාවන් මත බර වැඩි වීම.

අදාළත්වයේ විෂය පථය ආසන්න වශයෙන් බොළඳ ප්‍රවේශයට සමාන බව දැකිය හැකිය. අනුන්ගේ අනුකම්පා විරහිත සූරාකෑම හේතුවෙන් ඔබේ සේවාවේ කාර්ය සාධනය කිහිප වතාවක් වැඩි කිරීමට ඔබට අවශ්‍ය නම් සමාන්තර ඉල්ලීම් ක්‍රමය භාවිතා කිරීම අර්ථවත් කරයි. අපගේ උදාහරණයේ දී, කාර්ය සාධනය 2,5 ගුණයකින් වැඩි විය, නමුත් මෙය පැහැදිලිවම ප්රමාණවත් නොවේ.

හැඹිලිගත කිරීම

ඔබට බාහිර සේවාවන් සඳහා JPA හි ආත්මය තුළ හැඹිලිගත කළ හැකිය, එනම් ලැබුණු වස්තූන් නැවත නොලැබෙන පරිදි (කාණ්ඩ සැකසීමේදී ඇතුළුව) සැසියක් තුළ ගබඩා කරන්න. ඔබට එවැනි හැඹිලි සෑදිය හැක, ඔබට එහි @Cacheable සමඟ Spring භාවිතා කළ හැකිය, තවද ඔබට සැම විටම EhCache වැනි සූදානම් කළ හැඹිලියක් අතින් භාවිතා කළ හැක.

පොදු ගැටළුවක් වනුයේ හැඹිලි ප්‍රයෝජනවත් වන්නේ ඒවාට පහරක් ඇත්නම් පමණි. අපගේ නඩුවේදී, කර්තෘ ක්ෂේත්‍රයේ පහරවල් බොහෝ දුරට ඉඩ ඇත (අපි කියමු, 50%), නමුත් ලිපිගොනු මත කිසිදු පහරක් නොමැත. මෙම ප්රවේශය යම් වැඩිදියුණු කිරීම් ලබා දෙනු ඇත, නමුත් එය කාර්ය සාධනය රැඩිකල් ලෙස වෙනස් නොකරනු ඇත (සහ අපට ඉදිරි ගමනක් අවශ්ය වේ).

Intersession (දිගු) හැඹිලි සඳහා සංකීර්ණ අවලංගු කිරීමේ තර්කනය අවශ්‍ය වේ. පොදුවේ ගත් කල, ඔබ මැදිහත්වීමේ හැඹිලි භාවිතයෙන් කාර්ය සාධන ගැටළු විසඳීමට ප්‍රමාද වන තරමට වඩා හොඳය.

වාසි:

  1. කේතය වෙනස් නොකර හැඹිලිගත කිරීම ක්‍රියාත්මක කරන්න.
  2. ඵලදායිතාව කිහිප වතාවක් වැඩි කිරීම (සමහර අවස්ථාවලදී).

එය:

  1. වැරදි ලෙස භාවිතා කළහොත් කාර්ය සාධනය අඩු වීමේ හැකියාව.
  2. විශේෂයෙන්ම දිගු හැඹිලි සහිත විශාල මතකය උඩින්.
  3. සංකීර්ණ අවලංගු කිරීම්, ධාවන කාලය තුළ ප්‍රතිනිෂ්පාදනය කිරීමට අපහසු ගැටළු වලට තුඩු දෙන දෝෂ.

බොහෝ විට, හැඹිලි භාවිතා කරනුයේ සැලසුම් ගැටළු ඉක්මනින් විසඳීම සඳහා පමණි. ඒවා භාවිතා නොකළ යුතු බව මින් අදහස් නොවේ. කෙසේ වෙතත්, ඔබ සැමවිටම ඔවුන්ට ප්‍රවේශමෙන් සැලකිය යුතු අතර ප්‍රථමයෙන් ලැබෙන කාර්ය සාධන ප්‍රතිලාභය ඇගයීමට ලක් කළ යුතු අතර පසුව පමණක් තීරණයක් ගන්න.

අපගේ උදාහරණයේ දී, හැඹිලි මගින් 25% ක පමණ කාර්ය සාධන වැඩි වීමක් ලබා දෙනු ඇත. ඒ අතරම, හැඹිලිවල බොහෝ අවාසි ඇත, එබැවින් මම ඒවා මෙහි භාවිතා නොකරමි.

ප්රතිඵල

ඉතින්, අපි කණ්ඩායම් සැකසුම් භාවිතා කරන සේවාවක් බොළඳ ක්‍රියාත්මක කිරීමක් සහ එය වේගවත් කිරීමට සරල ක්‍රම කිහිපයක් දෙස බැලුවෙමු.

මෙම සියලු ක්රමවල ප්රධාන වාසිය වන්නේ සරලත්වයයි, එයින් බොහෝ ප්රසන්න ප්රතිවිපාක ඇත.

මෙම ක්‍රම සමඟ ඇති පොදු ගැටළුවක් වන්නේ දුර්වල ක්‍රියාකාරිත්වයයි, මූලික වශයෙන් පැකට් වල ප්‍රමාණය නිසා. එමනිසා, මෙම විසඳුම් ඔබට ගැලපෙන්නේ නැත්නම්, වඩාත් රැඩිකල් ක්රම සලකා බැලීම වටී.

ඔබට විසඳුම් සෙවිය හැකි ප්‍රධාන දිශාවන් දෙකක් තිබේ:

  • දත්ත සමඟ අසමමුහුර්ත වැඩ (පරම මාරුවක් අවශ්ය වේ, එබැවින් මෙම ලිපියේ සාකච්ඡා නොකෙරේ);
  • සමමුහුර්ත සැකසුම් පවත්වා ගනිමින් කාණ්ඩ විශාල කිරීම.

කණ්ඩායම් විශාල කිරීම බාහිර ඇමතුම් ගණන විශාල ලෙස අඩු කරනු ඇති අතර ඒ සමඟම කේතය සමමුහුර්තව තබා ගනී. ලිපියේ ඊළඟ කොටස මෙම මාතෘකාවට කැප කරනු ඇත.

මූලාශ්රය: www.habr.com

අදහස් එක් කරන්න