本文章由cartzhang编写。转载请注明出处。 所有权利保留。

文章链接:http://blog.csdn.net/cartzhang/article/details/55051570

作者:cartzhang

simple pool 博客一的地址:

http://blog.csdn.net/cartzhang/article/details/54096845

一、simpe_pool对象池的问题

在上篇对象池simple_pool中提到了它如今的问题。

一个是数据控制,也就是在单个父亲节点下,仅仅会一直增加来满足当前游戏对对象池内的对象数量的须要,没有考虑到降低。也就是说,若在A阶段,游戏场景中同一时候须要大量的某个池内O1对象,这时候就出现大量的AO1对象在内存中。可是过了A阶段,不须要A这么多O1对象时候,对象池内没有做操作和优化。

还有一个问题,就是多线程的问题。这个暂时不这里讨论。

有须要能够自己先对linkedlist加锁。



本片针对第一个问题。来做了处理。

顺便给出上篇simple_pool博客地址:

http://blog.csdn.net/cartzhang/article/details/54096845

https://github.com/cartzhang/simple_pool_bench

二、对象池内数量优化思路

本着在后台处理,尽量少影响对象池的使用的原则。决定使用在增加一个线程来实现。对须要清理的池内对象进行记录和推断。然后在主线程中进行删除(destroy)操作.



由于Unity不同意在其它自己建立的线程中调用Destroy函数,所以还是要在Update中进行处理。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2FydHpoYW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">



这个是自己画的流程图,基本就是这个样子。当然里面详细參数,能够依据自己须要调整。

三、实现代码

1.首先,建立垃圾清理标记和垃圾对象列表。

// garbage clean.
private static bool clearGarbageFlag = false;
private static List<Transform> GarbageList = new List<Transform>(100);

然后标记为真。開始清理。

这里进行了加锁,避免一边删除。一边增加,这样造成野的对象。垃圾表被清空了,对象也不在对象池内列表中。

2.主线程的清理工作

 private void Update()
{
CleanGarbageList();
} private void CleanGarbageList()
{
if (clearGarbageFlag)
{
clearGarbageFlag = false;
lock (GarbageList)
{
Debug.Assert(GarbageList.Count > 0);
Debug.Log("now destroy " + GarbageList.Count + " from pool" + GarbageList[0].name);
for (int i = 0; i < GarbageList.Count; i++)
{
Destroy(GarbageList[i].gameObject);
}
GarbageList.Clear();
}
}
}

3.优化线程启动



线程在第一次调用池的时候開始启动。

然后定时检測数量,每轮会检測checkTimesForEach个对象池内的未使用的情况。对象池个数超出的部分,等待5个中的一个多次检測没有异常后,在增加到检測中,这个主要是为了防止多个对象池内,一次性增加垃圾列表中太多对象。须要一次性删掉的太多,造成主线程卡顿的情况。



当然这也不是最理想的,为了防止卡顿。每次检測循环仅仅检測到一个满足垃圾清理条件,须要处理就会停止检測跳出循环,然后进行垃圾处理。这个也是为了轻量级的删减措施。

一旦成功设置标志。就又一次计算和检測。而且在设置后,优化线程等待1秒时间,来让主线程做工作。这个时间应该是非常充裕的。

主要代码

 private static void OptimizationPool()
{
// check cpu time to start
Thread.Sleep(100);
// 检測间隔时间20秒
float intervalTimeTodetect = 20f;
// after how many times counts to reset count.
// 循环检測多少次。后记录清零。 每次仅仅处理须要处理的前5个池。
const int checkTimesForEach = 5;
// 暂时池管理对象
Dictionary<int, ObjectPool> poolManagerTempDic = new Dictionary<int, ObjectPool>();
System.DateTime timeCount = System.DateTime.Now;
// 间隔时间内运行一次
bool eachMinuteGetDicOnce = false;
// 每一个池未使用对象超过一半的标记,记录次数
Dictionary<int, int> CurrentPoolUnuseCount = new Dictionary<int, int>();
// 检測刷新次数。也是一次计数的最大时间。
int icountLoopTime = 0;
Debug.Log("Thread start");
// 休眠时间
int sleepTime = 10;
while (isStartThread)
{
Thread.Sleep(sleepTime);
if (!eachMinuteGetDicOnce)
{
eachMinuteGetDicOnce = true;
poolManagerTempDic = poolManagerDic.ToDictionary(entry => entry.Key,entry => entry.Value);
// loop check 3 time to reset.
if (icountLoopTime % checkTimesForEach == 0)
{
CurrentPoolUnuseCount.Clear();
icountLoopTime = icountLoopTime > 10000000 ? 0 : icountLoopTime;
} // mark unuse nuber for all.
foreach(var element in poolManagerTempDic)
{
ObjectPool opool = element.Value;
int unusinglinkCount = opool.UnusingLinkedList.Count;
// half of all is useless and more than 10.
if (unusinglinkCount * 2 > unusinglinkCount + opool.UsingLinkedList.Count && unusinglinkCount > 10)
{
MarkCountForUnusingLink(ref CurrentPoolUnuseCount, element.Key);
// satisfy the condition,add unusing link gameobject to garbagelist.
int currentMark = 0;
CurrentPoolUnuseCount.TryGetValue(element.Key,out currentMark);
// be marked three times, add to garbage list.
if (currentMark >= 3)
{
AddObjectsToGarbageList(ref opool.UnusingLinkedList);
// count tick to reset.
CurrentPoolUnuseCount[element.Key] = 0;
clearGarbageFlag = true;
// each time only gathing one pool to process.
break;
}
}
}
}
// leave time for mainthread to delete gameobjects.
if (clearGarbageFlag)
{
icountLoopTime = 0;
intervalTimeTodetect = 20f;
Thread.Sleep(1000);
timeCount = System.DateTime.Now;
} // interval 20 seconds to start check once;
if ((System.DateTime.Now - timeCount).TotalSeconds > intervalTimeTodetect)
{
timeCount = System.DateTime.Now;
eachMinuteGetDicOnce = false;
poolManagerTempDic.Clear();
icountLoopTime++;
Debug.Log("Loop count is " + icountLoopTime);
}
// long time nothing happen, expand the detective interval time (max <= 90s).
if (icountLoopTime >= 4 )
{
intervalTimeTodetect = intervalTimeTodetect * 2 >= 90f ? 90f : intervalTimeTodetect * 2;
icountLoopTime = 0;
Debug.Log("interval time is " + intervalTimeTodetect);
}
}
return;
} /// <summary>
/// add last gameobject to garbagelist,as when unsing unusinglink is from first place to get.
/// </summary>
/// <param name="list"></param>
private static void AddObjectsToGarbageList(ref LinkedList<Transform> list)
{
Debug.Assert(list.Count > 0);
int FlagDestroyNumber = list.Count>>1;
for (int i = 0; i < FlagDestroyNumber; i++)
{
GarbageList.Add(list.Last.Value);
list.RemoveLast();
}
}

依照眼下设置參数,開始检測的时间间隔为20秒,若20*2=40秒后,没有须要处理的垃圾,就把检測时间间隔翻倍为40秒检測一次;若在过40*4=160秒,没有触发标志。检測时间进一步延长,逐次翻倍增加。可是最大值为90秒。

也就是说。最大的检測间隔为90秒。



若中间被打断。所有归为正常20秒检測一次。

触发增加垃圾列表的条件:



设置触发标志是一个池,在3次检測中都有超过一半的对象没有被使用,而且总体未使用数量超过10个。

四、更新project分享地址:

地址:https://github.com/cartzhang/simple_pool_bench



能够下载Assets文件。然后用unity測试。



这个測试demo为 PoolTimeOptimizeOjbectsDemo.unity。



优化流程图下载地址:

https://github.com/cartzhang/simple_pool_bench/blob/master/img/pool_bench_optimize.png



若有问题,请提交问题或代码。非常感谢!

。!

五、附件

poolManager.cs 所有代码:

using UnityEngine;
using System.Collections.Generic;
using SLQJ_POOL;
using UnityEngine.Internal;
using System.Threading;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Linq; /// <summary>
/// 扩展GameObject函数
/// 使用扩展函数方面代码调用,能够Unity的随意代码中,调用对象池来产生和回池对象,
/// 而且不须要调用命名空间等繁琐东西。 /// 代码样例: obj = gameObject.InstantiateFromPool(prefab);
/// gameObject.DestroyToPool(poolObjs[poolObjs.Count - 1], 0.2f);
/// 详细能够參考HowToUse脚本和TestEffect。 /// @cartzhang
/// </summary>
public static class GameObjectExten
{
/// <summary>
/// 调用对象池,产生一对象,并带有位置和旋转等參考
/// </summary>
/// <param name="gameobject"></param>
/// <param name="original"></param>
/// <param name="position"></param>
/// <param name="rotation"></param>
/// <returns></returns>
public static GameObject InstantiateFromPool(this GameObject gameobject, Object original, Vector3 position, Quaternion rotation)
{
return PoolManager.PullObjcetFromPool(original as GameObject, position, rotation).gameObject;
}
/// <summary>
/// 调用对象池,产生对象
/// </summary>
/// <param name="gameobject"></param>
/// <param name="original"></param>
/// <returns></returns>
public static GameObject InstantiateFromPool(this GameObject gameobject, Object original)
{
return PoolManager.PullObjcetFromPool(original as GameObject).gameObject;
}
/// <summary>
/// 对象返回对象池
/// </summary>
/// <param name="gameobject"></param>
/// <param name="obj"></param>
public static void DestroyToPool(this GameObject gameobject, Object obj)
{
PoolManager.PushObjectPool((obj as GameObject).transform);
}
/// <summary>
/// 带延时的返回对象池
/// </summary>
/// <param name="gameobject"></param>
/// <param name="obj"></param>
/// <param name="t"></param>
public static void DestroyToPool(this GameObject gameobject, Object obj, [DefaultValue("0.0F")] float t)
{
PoolManager.PushObjectPool((obj as GameObject).transform, t);
}
} namespace SLQJ_POOL
{
public class PoolManager : MonoBehaviour
{
private static PoolManager instance;
private static bool bStartThreadOnce = false;
private static bool isStartThread = false;
private static Thread tOptimizationThread; private static List<GameObject> prefabList = new List<GameObject>();
//存放预制体相应的id。ObjcetPool
public static Dictionary<int, ObjectPool> poolManagerDic = new Dictionary<int, ObjectPool>();
private static Dictionary<Transform, ObjectPool> transformDic = new Dictionary<Transform, ObjectPool>();
// garbage clean.
private static bool clearGarbageFlag = false;
private static List<Transform> GarbageList = new List<Transform>(100);
private void Update()
{
CleanGarbageList();
} private void CleanGarbageList()
{
if (clearGarbageFlag)
{
clearGarbageFlag = false;
lock (GarbageList)
{
Debug.Assert(GarbageList.Count > 0);
Debug.Log("now destroy " + GarbageList.Count + " from pool" + GarbageList[0].name);
for (int i = 0; i < GarbageList.Count; i++)
{
Destroy(GarbageList[i].gameObject);
}
GarbageList.Clear();
}
}
} //初始化某个预制体相应的对象池
public static void InitPrefab(GameObject prefab, int initNum = 4)
{
GetObjectPool(prefab, initNum);
}
//外界调用的接口
public static Transform PullObjcetFromPool(GameObject prefab)
{
return _PullObjcetFromPool(prefab);
}
public static Transform PullObjcetFromPool(GameObject prefab, Vector3 pos, Quaternion quaternion)
{
return _PullObjcetFromPool(prefab, pos, quaternion);
}
private static Transform _PullObjcetFromPool(GameObject prefab)
{
if (prefab == null)
{
Debug.Log("prefab is null!");
return null;
}
ObjectPool objPool = GetObjectPool(prefab);
StartThreadOnce();
return objPool.PullObjcetFromPool();
} private static Transform _PullObjcetFromPool(GameObject prefab, Vector3 pos, Quaternion quaternion)
{
if (prefab == null)
{
Debug.Log("prefab is null!");
return null;
}
ObjectPool objPool = GetObjectPool(prefab, pos, quaternion);
StartThreadOnce();
return objPool.PullObjcetFromPool(pos, quaternion);
} private static ObjectPool GetObjectPool(GameObject prefab, int initNum = 4)
{
ObjectPool objPool = null;
//推断集合中是否有预制体相应的对象池
int leng = prefabList.Count;
int prefabID = prefab.GetInstanceID();
for (int i = 0; i < leng; i++)
{
if (prefabID == prefabList[i].GetInstanceID())
{
objPool = poolManagerDic[prefabID];
break;
}
}
//没有找到对象池的话创建一个对象池
if (objPool == null)
{
objPool = CreatObjcetPool(prefab, initNum);
}
return objPool;
} private static ObjectPool GetObjectPool(GameObject prefab, Vector3 pos, Quaternion qua, int initNum = 4)
{
ObjectPool objPool = null;
int leng = prefabList.Count;
int prefabID = prefab.GetInstanceID();
for (int i = 0; i < leng; i++)
{
if (prefabID == prefabList[i].GetInstanceID())
{
objPool = poolManagerDic[prefabID];
}
}
if (objPool == null)
{
objPool = CreatObjcetPool(prefab, pos, qua, initNum);
}
return objPool;
} private static ObjectPool CreatObjcetPool(GameObject prefab, Vector3 pos, Quaternion qua, int initNum)
{
prefabList.Add(prefab);
GameObject go = new GameObject();
go.name = prefab.name + "Pool";
ObjectPool objPool = go.AddComponent<ObjectPool>();
objPool.InitObjectPool(prefab, pos, qua, transformDic, initNum);
poolManagerDic.Add(prefab.GetInstanceID(), objPool);
return objPool;
} private static ObjectPool CreatObjcetPool(GameObject prefab, int initNum)
{
prefabList.Add(prefab);
GameObject go = new GameObject();
go.name = prefab.name + "Pool";
ObjectPool objPool = go.AddComponent<ObjectPool>();
objPool.InitObjectPool(prefab, transformDic, initNum);
poolManagerDic.Add(prefab.GetInstanceID(), objPool);
return objPool;
} public static void PushObjectPool(Transform handleTransform)
{
ObjectPool objPool = GetPoolByTransform(handleTransform);
if (objPool)
{
objPool.PushObjectToPool(handleTransform);
}
else
{
GameObject.Destroy(handleTransform.gameObject);
}
}
public static void PushObjectPool(Transform handleTransform, float delayTime)
{
ObjectPool objPool = GetPoolByTransform(handleTransform);
if (objPool)
{
objPool.PushObjectToPool(handleTransform, delayTime);
}
else
{
GameObject.Destroy(handleTransform.gameObject, delayTime);
}
}
//马上回池的接口
public static void PushObjectPool(Transform handleTransform, GameObject prefab)
{
ObjectPool objPool = GetObjectPool(prefab);
objPool.PushObjectToPool(handleTransform.transform);
}
//延迟回池的接口
public static void PushObjectPool(Transform handleTransform, GameObject prefab, float delayTime)
{
ObjectPool objPool = GetObjectPool(prefab);
objPool.PushObjectToPool(handleTransform, delayTime);
} private static ObjectPool GetPoolByTransform(Transform handleTransform)
{
if (transformDic.ContainsKey(handleTransform))
{
return transformDic[handleTransform];
}
Debug.LogError(handleTransform.name + " no find it's ObjectPool");
return null;
}
// add code to clean pool from time to time.
private static void StartThreadOnce()
{
// start thread to clean pool from time to time.
if (!bStartThreadOnce)
{
bStartThreadOnce = true;
ThreadPool.QueueUserWorkItem(AutoToCheckOptimization);
}
} private static void AutoToCheckOptimization(object obj)
{
Thread.Sleep(10);
isStartThread = true;
tOptimizationThread = new Thread(OptimizationPool);
tOptimizationThread.Start();
} private static void OptimizationPool()
{
// check cpu time to start
Thread.Sleep(100);
// 检測间隔时间20秒
float intervalTimeTodetect = 20f;
// after how many times counts to reset count.
// 循环检測多少次,后记录清零。每次仅仅处理须要处理的前5个池。
const int checkTimesForEach = 5;
// 暂时池管理对象
Dictionary<int, ObjectPool> poolManagerTempDic = new Dictionary<int, ObjectPool>();
System.DateTime timeCount = System.DateTime.Now;
// 间隔时间内运行一次
bool eachMinuteGetDicOnce = false;
// 每一个池未使用对象超过一半的标记,记录次数
Dictionary<int, int> CurrentPoolUnuseCount = new Dictionary<int, int>();
// 检測刷新次数。也是一次计数的最大时间。 int icountLoopTime = 0;
Debug.Log("Thread start");
// 休眠时间
int sleepTime = 10;
while (isStartThread)
{
Thread.Sleep(sleepTime);
if (!eachMinuteGetDicOnce)
{
eachMinuteGetDicOnce = true;
poolManagerTempDic = poolManagerDic.ToDictionary(entry => entry.Key,entry => entry.Value);
// loop check 3 time to reset.
if (icountLoopTime % checkTimesForEach == 0)
{
CurrentPoolUnuseCount.Clear();
icountLoopTime = icountLoopTime > 10000000 ? 0 : icountLoopTime;
} // mark unuse nuber for all.
foreach(var element in poolManagerTempDic)
{
ObjectPool opool = element.Value;
int unusinglinkCount = opool.UnusingLinkedList.Count;
// half of all is useless and more than 10.
if (unusinglinkCount * 2 > unusinglinkCount + opool.UsingLinkedList.Count && unusinglinkCount > 10)
{
MarkCountForUnusingLink(ref CurrentPoolUnuseCount, element.Key);
// satisfy the condition,add unusing link gameobject to garbagelist.
int currentMark = 0;
CurrentPoolUnuseCount.TryGetValue(element.Key,out currentMark);
// be marked three times, add to garbage list.
if (currentMark >= 3)
{
AddObjectsToGarbageList(ref opool.UnusingLinkedList);
// count tick to reset.
CurrentPoolUnuseCount[element.Key] = 0;
clearGarbageFlag = true;
// each time only gathing one pool to process.
break;
}
}
}
}
// leave time for mainthread to delete gameobjects.
if (clearGarbageFlag)
{
icountLoopTime = 0;
intervalTimeTodetect = 20f;
Thread.Sleep(1000);
timeCount = System.DateTime.Now;
} // interval 20 seconds to start check once;
if ((System.DateTime.Now - timeCount).TotalSeconds > intervalTimeTodetect)
{
timeCount = System.DateTime.Now;
eachMinuteGetDicOnce = false;
poolManagerTempDic.Clear();
icountLoopTime++;
Debug.Log("Loop count is " + icountLoopTime);
}
// long time nothing happen, expand the detective interval time (max <= 90s).
if (icountLoopTime >= 4 )
{
intervalTimeTodetect = intervalTimeTodetect * 2 >= 90f ? 90f : intervalTimeTodetect * 2;
icountLoopTime = 0;
Debug.Log("interval time is " + intervalTimeTodetect);
}
}
return;
} private static void MarkCountForUnusingLink(ref Dictionary<int, int> poolUnuseCount,int prefabGuid)
{
Debug.Assert(null != poolManagerDic);
int currentMark = 0;
if (poolUnuseCount.ContainsKey(prefabGuid))
{
poolUnuseCount.TryGetValue(prefabGuid, out currentMark);
}
currentMark++;
if (poolUnuseCount.ContainsKey(prefabGuid))
{
poolUnuseCount[prefabGuid] = currentMark;
}
else
{
poolUnuseCount.Add(prefabGuid, currentMark);
}
} /// <summary>
/// add last gameobject to garbagelist,as when unsing unusinglink is from first place to get.
/// </summary>
/// <param name="list"></param>
private static void AddObjectsToGarbageList(ref LinkedList<Transform> list)
{
Debug.Assert(list.Count > 0);
int FlagDestroyNumber = list.Count>>1;
for (int i = 0; i < FlagDestroyNumber; i++)
{
GarbageList.Add(list.Last.Value);
list.RemoveLast();
}
} public void Dispose()
{
isStartThread = false;
}
}
}

simple_pool对象池——优化&lt;二&gt;的更多相关文章

  1. Unity 游戏框架搭建 (二十) 更安全的对象池

    上篇文章介绍了,只需通过实现IObjectFactory接口和继承Pool类,就可以很方便地实现一个SimpleObjectPool.SimpleObjectPool可以满足大部分的对象池的需求.而笔 ...

  2. 二十、dbms_stats(用于搜集,查看,修改数据库对象的优化统计信息)

    1.概述 作用:用于搜集,查看,修改数据库对象的优化统计信息. 2.包的组成 1).get_column_stats作用:用于取得列的统计信息语法:dbms_stats.get_column_stat ...

  3. Unity性能优化-对象池

    1.对象池Object Pool的原理: 有些GameObject是在游戏中需要频繁生成并销毁的(比如射击游戏中的子弹),以前的常规做法是:Instantiate不断生成预设件Prefab,然后采用碰 ...

  4. Mysql线程池优化笔记

    Mysql线程池优化我是总结了一个站长的3篇文章了,这里我整理到一起来本文章就分为三个优化段了,下面一起来看看.     Mysql线程池系列一(Thread pool FAQ) 首先介绍什么是mys ...

  5. Unity 对象池的使用

    在游戏开发过程中,我们经常会遇到游戏发布后,测试时玩着玩着明显的感觉到有卡顿现象.出现这种现象的有两个原因:一是游戏优化的不够好或者游戏逻辑本身设计的就有问题,二是手机硬件不行.好吧,对于作为程序员的 ...

  6. Unity 游戏框架搭建 (十九) 简易对象池

    在Unity中我们经常会用到对象池,使用对象池无非就是解决两个问题: 一是减少new时候寻址造成的消耗,该消耗的原因是内存碎片. 二是减少Object.Instantiate时内部进行序列化和反序列化 ...

  7. Java小对象的解决之道——对象池(Object Pool)的设计与应用

    一.概述 面向对象编程是软件开发中的一项利器,现已经成为大多数编程人员的编程思路.很多高级计算机语言也对这种编程模式提供了很好的支持,例如C++.Object Pascal.Java等.曾经有大量的软 ...

  8. 大数据技术之_27_电商平台数据分析项目_02_预备知识 + Scala + Spark Core + Spark SQL + Spark Streaming + Java 对象池

    第0章 预备知识0.1 Scala0.1.1 Scala 操作符0.1.2 拉链操作0.2 Spark Core0.2.1 Spark RDD 持久化0.2.2 Spark 共享变量0.3 Spark ...

  9. netty源码分析 - Recycler 对象池的设计

    目录 一.为什么需要对象池 二.使用姿势 2.1 同线程创建回收对象 2.2 异线程创建回收对象 三.数据结构 3.1 物理数据结构图 3.2 逻辑数据结构图(重要) 四.源码分析 4.2.同线程获取 ...

随机推荐

  1. 【模拟】Friday the Thirteenth

    题目描述 Is Friday the 13th really an unusual event?That is, does the 13th of the month land on a Friday ...

  2. ReactiveCocoa(一)

    前言 之前总听别人说什么Reactive Cocoa + MVVM,但是没有找到讲解Reactive Cocoa相关的资料.结果进入新公司,项目里面有部分代码使用到了Reactive Cocoa,所以 ...

  3. luogu P3818 小A和uim之大逃离 II

    题目背景 话说上回……还是参见 https://www.luogu.org/problem/show?pid=1373 吧 小a和uim再次来到雨林中探险.突然一阵南风吹来,一片乌云从南部天边急涌过来 ...

  4. ACM集训日志——day1——15.7.8

    UVA 11292 The Dragon of Loowater 题意 给n个头,m个骑士,骑士有能力值x,代表他可以砍掉一个直径不超过x的头,并且佣金为x,求要砍掉所有的头,需要的最少佣金是多少. ...

  5. Servlet笔记2-文件上传

    Servlet上传文件: Servlet 3.0改进了部分API,其中HttpServletRequest增加了对文件上传的支持. HttpServletRequest提供了两个方法来处理文件上传: ...

  6. 代理模式(Proxy)--动态代理(JDK)

    在是上一篇博客中实现了静态代理. 在上篇的结尾提到了一个问题: 思考:如果我们下需要对火车,自行车实现相同的代理,我们又该如何实现呢? 这篇博客就来解决这个问题: 解决这类问题需要用到动态代理技术,实 ...

  7. linux-网络监控命令-netstat进阶

    2.网络连接状态详解共有12中可能的状态,前面11种是按照TCP连接建立的三次握手和TCP连接断开的四次挥手过程来描述的.1).LISTEN:首先服务端需要打开一个socket进行监听,状态为LIST ...

  8. 玩转Nuget服务器搭建(三)

    前两篇已经介绍了如何打包.如何搭建nuget server web站点,接下来让我们介绍一下,如何在我们的vs中访问我们自己搭建的nuget服务器中的包. vs访问我们自己的nuget服务器中的包   ...

  9. zabbix agent监控主机配置

    zabbix agent监控主机配置 环境说明 系统版本    CentOS 7.2 x86_64 软件版本    zabbix 3.0.18   1.监控zabbix服务器端 1.1 安装zabbi ...

  10. 转: Eclispe的远程开发

    from: http://www.thinksaas.cn/topics/0/528/528009.html 新项目中用到了所谓的Eclipse远程开发.参考: http://www.eclipse. ...