MMORPG大型游戏设计与开发(服务器 游戏场景 多线程)

时间:2022-11-21 18:02:00

多线程在随着cpu发展应用的是越来越多,游戏场景因为其在服务器所占的数据量与逻辑复杂度的原因必须依赖于它。为什么场景要采用多线程?场景的线程是怎样的?场景的线程又是如何创建的?场景的线程又是怎样管理的?在这里同时对可以指正错误的朋友们说声谢谢,虽然是小错误,也希望大家能够勇于纠正这些错误。

 游戏截图

MMORPG大型游戏设计与开发(服务器 游戏场景 多线程)

MMORPG大型游戏设计与开发(服务器 游戏场景 多线程)

采用理由

  上面的两张截图分别在不同的场景,试想一下如果一个线程只能先处理其中一张图的数据,后果会怎么样?

  单线程往往需要等待,就好像我们到银行窗口办理业务的时候,以前的时候很多网点只有一个窗口,所以我们不得不排队等候,然而随着时代的进步银行的窗口随着业务的开展越来越多,更多的业务员使得我们省去了排队的烦恼。而游戏场景在游戏中处理的逻辑是最为复杂的,特别是一些大场景的数据那更是多不胜数,程序处理逻辑数据需要时间,在单线程里面对复杂的逻辑就需要等待不少的时间,数据和逻辑越复杂其等待的时间就会越长,你想如果我们在玩游戏的时候在A场景的时候,B场景因为要等待A场景的逻辑处理完成后才能够处理其场景的数据,也就是说A场景的人先走动完成后,B场景的玩家才能走动。
  为了让所有场景的数据都能在较短的时间内处理,我们就需要更多的处理者来帮忙,也就是我们拥有更多的线程来处理,如果只有一个线程处理N个场景当然很慢,如果有M个场景同时处理N个场景速度则会大大提高,这就是我们之所以选择多线程的原因。而且一个线程所能承受的场景数量,往往是跟场景的数据量大小以及复杂度有关。

场景多线程

  1、线程管理器(manager)

    用于添加场景线程并初始化线程数据。

  2、线程池(pool)

    多个线程数据的集合管理。

  3、线程分配(thread)

    这个世界上最理想的是有足够的资源,就像这里一样每个线程负责一个场景就是最理想的,因为这样效率是最高的。线程越多消耗的CPU自然成正比例的增加,就好像地球上的资源一样,没有办法完全的满足需求一样,这样我们就必须想办法进行资源共享,一个线程负责多个场景。记得小时候的劳动课一样,有时候工具不够的情况下,老师往往会将同学们分成几组,每组共享那些工具,但是有的时候一个工具分了很多人使用,超过了负荷的时候就达不到老师的要求(比如老师要求规定时间内每个人都要使用工具多少次,因为人数太多甚至有的人工具都碰不到)。

    线程的负载主要表现在程序执行的快慢和效率上,如果效率明显很低影响到了正常的工作,我们就不得不想办法提升效率。最直接影响场景线程的负载的便是负责场景数量,所以场景线程有规定的场景上限。

一般流程

  场景管理器创建所有场景(scene manager)->线程池对象初始化(thread pool)->线程管理器分配场景线程(thread manager)->场景线程管理器运行所有线程(thread manager)

算法(交换排序)

  1、冒泡排序(bubble sort)

    交换相邻的两个元素,将最大的元素逐渐移动到最后,如果数组大小为N,则N次之后数组则变为有序的数组。泡排序算法主要用于排序元素较少且时间要求不太高的场合。这里进行了算法改进:增加一个标记,如果已经没有需要交换的元素则后面不需再排序。

    code.

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

/**
 * 交换相邻的两个元素,将最大的元素逐渐移动到最后,如果数组大小为N,则N次之后数组则变为有序的数组
 * 冒泡排序算法主要用于排序元素较少且时间要求不太高的场合
 * 算法改进:增加一个标记,如果已经没有需要交换的元素则后面不需再排序
 */ 

void printarray(int32_t array[], int32_t length);
void bubblesort(int32_t array[], int32_t length);

int32_t main(int32_t argc, char *argv[]) {
  int32_t array[] = {3, 13, 8, 9, 76, 45, 56, 99, 102, 15};
  int32_t length = sizeof(array) / sizeof(array[0]);
  bubblesort(array, length);  
  return 0;
}

void printarray(int32_t array[], int32_t length) {
  int32_t i;
  for (i = 0; i < length; ++i)
    printf("%4d", array[i]);
  printf("\n");
}

void bubblesort(int32_t array[], int32_t length) {
  int32_t i, j;
  int32_t temp;
  uint8_t flag = 1;
  for (i = 1; i < length && 1 == flag; ++i) {
    flag = 0;
    for (j = 0; j < length - i; ++j) {
      if (array[j] > array[j + 1]) {
        temp = array[j];
        array[j] = array[j + 1];
        array[j + 1] = temp;
        flag = 1;
      }
    }
    printf("the %d times result: ", i);
    printarray(array, length);
  }
}

    result.

MMORPG大型游戏设计与开发(服务器 游戏场景 多线程)

  2、快速排序(quick sort)

    快速排序算法是冒泡排序算法的改进,但是实现却比冒泡复杂很多,它主要针对大数据排序,果对时间要求不是很高可以使用直接插入排序或者冒泡排序。其特点是排序的时间效率比较高,并且在特别大的数据量时十分明显。同希尔算法一样,快速排序是一种不太稳定的算法,和其实现的原理有关。

    code.

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

/**
 * 快速排序算法是冒泡排序算法的改进,但是实现却比冒泡复杂很多,它主要针对大数据排序,
 * 如果对时间要求不是很高可以使用直接插入排序或者冒泡排序
 * 其特点是排序的时间效率比较高,并且在特别大的数据量时十分明显。
 * 同希尔算法一样,快速排序是一种不太稳定的算法,和其实现的原理有关。
 */ 

//数组打印
void displayarray(int32_t array[], int32_t length);
//输出每次划分的结果
void _displayarray(int32_t array[], int32_t length, int32_t pivot, int32_t count);
//快速排序核心实现
void _quicksort(int32_t array[], int32_t length, int32_t low, int32_t high);
//快速排序函数,对数组的元素进行排序
void quicksort(int32_t array[], int32_t length);
//对素组array[low...high]的元素进行一趟排序,使枢轴前面的元素小于枢轴元素,
//枢轴后面的元素大于等于枢轴元素,并返回枢轴元素
int32_t partition(int32_t array[], int32_t low, int32_t high);

int32_t main(int32_t argc, char *argv[]) {
  int32_t array[] = {3, 15, 7, 3, 2, 11, 9, 33, 35, 18, 32};
  int32_t length = sizeof(array) / sizeof(array[0]);
  printf("before sort: ");
  displayarray(array, length);
  quicksort(array, length);
  printf("after sort: ");
  displayarray(array, length);
  return 0;
}

void displayarray(int32_t array[], int32_t length) {
  int32_t i;
  for (i = 0; i < length; ++i)
    printf("%4d", array[i]);
  printf("\n");
}

void _displayarray(int32_t array[], 
                   int32_t length, 
                   int32_t pivot, 
                   int32_t count) {
  int32_t i;
  printf("the %d times result: [", count);
  for (i = 0; i < pivot; ++i)
    printf("%-4d", array[i]);
  printf("]");
  printf("%3d ", array[pivot]);
  printf("[");
  for (i = pivot + 1; i < length; ++i)
    printf("%-4d", array[i]);
  printf("]");
  printf("\n");
}

void _quicksort(int32_t array[], int32_t length, int32_t low, int32_t high) {
  int32_t pivot;
  static int32_t count = 1;
  if (low < high) { //如果元素序列的长度大于1
    pivot = partition(array, low, high); //将待排序序列array[low...high]划分为两部分
    _displayarray(array, length, pivot, count); //输出每次划分的结果
    ++count;
    _quicksort(array, length, low, pivot - 1); //对左边的子表进行递归排序,pivot是枢轴位置
    _quicksort(array, length, pivot + 1, high); //对右边的子表进行递归排序
  }
}

void quicksort(int32_t array[], int32_t length) {
  _quicksort(array, length, 0, length - 1);
}

int32_t partition(int32_t array[], int32_t low, int32_t high) {
  int32_t temp, pivot;
  pivot = array[low]; //将第一个元素作为枢轴元素
  temp = array[low];
  while (low < high) { //从表的两端交替的向中间扫描
    while (low < high && array[high] >= pivot) //从表的末端向前扫描
      --high;
    if (low < high) { //将当前high指向的元素保存在low位置
      array[low] = array[high];
      ++low;
    }
    while (low < high && array[low] <= pivot) //从表的开始向后扫描
      ++low;
    if (low < high) { //将当前low指向的元素保存在high位置
      array[high] = array[low];
      --high;
    }
    array[low] = temp;
  }
  return low;
}

    result.

MMORPG大型游戏设计与开发(服务器 游戏场景 多线程)