.Net 如何模拟会话级此外信号量,对http接口调用频率举办限定(有demo)葡京在线开户

近期,因为各样因素,你无法不对一个伸手或者措施举办频率上的访问限制。
诸如,
你对外提供了一个API接口,注册用户每分钟最多可以调用100次,非注册用户每分钟最多可以调用10次。
诸如,
有一个老大吃服务器资源的章程,在平等时刻无法领先10私有调用这么些点子,否则服务器满载。
譬如, 有一些例外的页面,访客并无法反复的访问或发言。
譬如说, 秒杀活动等展开。
比如
,防范DDOS,当达到自然频率后调用脚本iis服务器ip黑名单,防火墙黑名单。
如上各样的比方,也就是说,咋样从一个断面的角度对调用的情势开展频率上的限量。而对效用限制,服务器层面都有最直白的解决形式,现在本人说的则是代码层面上的功用管控。

学学工作不知晓有怎样意思,找不到人生方向?

是在大集团混履历仍然出去创业,人生抉择太多陷入焦虑?

在该校当了N年学霸,毕业未来秒变职场小白,心里落差巨大?

困于工作倦怠期,不甘于稳定却庸碌的现状,可又不敢辞职去追逐理想?

正文给出六个示范,一个是依照单机环境的兑现,第二个则是据悉分布式的Redis实现

建立十八年来,BeBeyond见过太多的人,在生意发展的进程中,碰着以上的这几个瓶颈,并来向大家求助。


大家发现在面对这多少个困境的时候,他们多次都是病急乱投医。或者领会对象的见识,或者跟家长谈谈心,或者就是在网上一阵疯狂搜索…当然,结果当然是很难取得其他争持时有价值的信息。

以第一个API接口需求为例,先说下单机环境下的实现。
遵照惯性思维,我们自然会想到缓存的过期策略这种艺术,然则严谨来讲就HttpRuntime.Cache而言,通过缓存的晚点策略来对请求举办频率的现身控制是不合适的。
  HttpRuntime.Cache
是应用程序级其余Asp.Net的缓存技术,通过这些技能可以声明五个缓存对象,可以为各类对象设置过期时间,当过期时刻到达后该缓存对象就会收敛(也就是当你拜访该对象的时候为Null)

由此,真的存在怎么样直接快速的点子可以急迅击破桎梏打通面对生意困境时打断的心力吗?

  为何如此说吗?比如对某个方法(方法名:GetUserList)咱们要开展1分钟最多10次的界定,现在我们就新建一个int型的Cache对象,然后设置1分钟后过期消失。那么每当访问GetUserList方法前,大家就先判断那个Cache对象的值是否超过10,假设超过10就不实施GetUserList方法,假设低于10则允许实施。每当访问该对象的时候假如不设有或者逾期就新建,这样循环,则该对象永远不容许跨越10。

当!然!有!

1   if ((int)HttpRuntime.Cache["GetUserListNum"] > 10) //大于10请求失败
2   {
3      Console.WriteLine("禁止请求");
4   }
5   else
6   {
7      HttpRuntime.Cache["GetUserListNum"] = (int)HttpRuntime.Cache["GetUserListNum"] + 1; //否则该缓存对象的值+1
8      Console.WriteLine("允许请求");
9   }

前段时间我们生产了一篇洋洋洒洒7000字的事情白皮书为远在迷茫的众人进行职业启蒙拿到了豪门普遍的好评!

如此那般的想念及贯彻相对来说分外简单,可是依据这样的一个模子设定,那么就会冒出那种情状:

收藏 |
每个中华大学生都应有读的饭碗启蒙白皮书

 葡京在线开户 1

而这三回BeBeyond于2018祭灶节之始,将让10000+人都找到好办事的线下课的想想系列,第一次搬到了线上来,与简书联合重磅推出的葡京在线开户,「职业小课堂」

 

把已经仅仅属于个别人追寻自我提升,解决事情发展迷茫的要诀与更多的人分享。

如上图,每个点代表一遍访问请求,我在0秒的时候
新建了一个名字为GetUserListNum的缓存对象。
在0~0.5秒之内
我访问了3次,在0.5~1秒之内,我们访问了7次。此时,该目的消失,然后我们跟着访问,该对象重置为0.
              
 在第1~1.5秒之内,如故访问了7次,在第1.5秒~2秒之内做客了3次。

(P.S.文末有惊喜福利)

据悉这种简易缓存过期策略的模型,在这2分钟内,大家即使平均每分钟都访问了10次,满意这多少个规定,不过如果我们从中取一个之内段,0.5秒~1.5秒之内,也是1分钟,不过却实实在在的拜访了14次!远远超过了大家设置的
1分钟最多访问10次的 限制。


 

在这多少个高速时代,人们天天陀螺版运转,大家觉得一个高质地的节拍课程,会是顿时最节省时间成本和流量成本的就学情势。

这就是说咋样正确的来化解地点的题目吧?大家得以因此模拟对话级另外信号量这一手法,这也就是大家明天的核心了。
   什么是信号量?仅就以代码而言,  static
SemaphoreSlim semaphoreSlim = new SemaphoreSlim(5); 
它的趣味就表示在多线程情形下,在其它一随时,只好同时5个线程去拜谒。

但是,在这些线上课如密西西比河沙数般冒尖,铺面而来的时日,纵观市场上已部分事情内容,不乏噱头(比如咪蒙教你月薪5万之流),却很少看到深度挖掘问题本质的上乘内容。

 

有关职业问题的分析,BeBeyond曾经探索了18年,我们积累为100000+的求职者举办过职业咨询,并且8000+的学员在此间找到了投机前途的差事发展之路。

4容器4线程模型

前几天,在贯彻代码的先头我们先规划一个模型。

葡京在线开户 2

  假设大家有一个用户A的管道,这么些管道里装着用户A的请求,比如用户A在一秒钟发出了10次呼吁,那么每一个请求过来,管道里的因素都会多一个。可是大家设定这些管道最两只好容纳10个元素,而且每个元素的存活期为1秒,1秒后则该因素消失。那么这么设计的话,无论是速率依然多少的突进,都会有管道长度的范围。这样一来,无论从哪一个光阴节点依旧时间距离出发,这些管道都能知足我们的功效限制需求。

而这里的管道,就必须和会话Id来对号入座了。每当有新会话进来的时候就生成一个新管道。那么些会话id依据自己场景所定,可以是sessionId,可以是ip,也足以是token。

那么既然那一个管道是会话级其它,我们终将得需要一个器皿,来装那个管道。现在,我们以IP来定名会话管道,并把具有的管道都装载在一个器皿中,如图

葡京在线开户 3

而按照刚才的设定,大家还需要对容器内的每条管道的要素举办拍卖,把过期的给删除掉,为此,还亟需独自为该容器开辟出一个线程来为每条管道展开元素的清理。而当管道的元素为0时,我们就清掉该管道,以便节省容器空间。

 葡京在线开户 4

理所当然,由于用户量多,一个容器内可能存在上万个管道,那么些时候只是用一个容器来装载来清理,在功用上显然是不够的。这一个时候,大家就得对容器举行横向增加了。

  比如,大家可以按照Cpu核心数自动生成对应的多寡的容器,然后依据一个算法,对IP来展开导流。我眼前cpu是4个逻辑主题,就生成了4个容器,每当用户访问的时候,都会首先经过一个算法,这么些算法会对IP举办处理,如192.168.1.11~192.168.1.13以此Ip段进第一个容器,xxx~xxx进第二个容器,依次类推,相应的,也就有了4个线程去分别处理4个容器中的管道。

葡京在线开户 5

 

那么,最后就形成了我们的4容器4线程模型了。

今昔,着眼于编码实现:

  首先我们需要一个能承载这么些器皿的载体,这么些载体类似于连接池的概念,可以按照部分需要自动生成适应数量的容器,假若有特殊要求的话,还足以在容器上切出一个器皿管理的面,在线程上切出一个线程管理的面以便于实时监察和调度。尽管真要做这么一个系统,那么
容器的调度 和 线程的调度功用是必要的,而本Demo则是到位了重要职能,像容器和线程在代码中我也没剥离开来,算法也是直接写死的,实际设计中,对算法的宏图依旧很重大的,还有多线程模型中,怎么着上锁才能让效用最大化也是重点的。

而这里为了案例的直观就直接写死成4个容器。

public static List<Container> ContainerList = new List<Container>(); //容器载体
static Factory()
{
     for (int i = 0; i < 4; i++)
     {
        ContainerList.Add(new Container(i));  //遍历4次  生成4个容器
     }
     foreach (var item in ContainerList)
     {
        item.Run();    //开启线程
     }
}

现在,我们只要 有编号为 0 到 40 这样的 41个用户。那么这么些导流算法
我也就间接写死,编号0至9的用户
将他们的伸手给抛转到第一个容器,编号10~19的用户
放到第二个容器,编号20~29放到第几个容器,编号30~40的用户放到第四个容器。

那么这几个代码就是这么的:

 static Container GetContainer(int userId, out int i) //获取容器的算法
 {
     if (0 <= userId && userId < 10)    //编号0至9的用户  返回第一个容器  依次类推
     {
          i = 0;
          return ContainerList[0];
     }
     if (10 <= userId && userId < 20)
     {
          i = 1;
          return ContainerList[1];
     }
     if (20 <= userId && userId < 30)
     {
          i = 2;
          return ContainerList[2];
      }
      i = 3;
      return ContainerList[3];
  }

当大家的对话请求经过算法的导流之后,都必须调用一个格局,用于辨别管道数量。倘使管道数量已经不止10,则呼吁战败,否则成功

  public static void Add(int userId)
  {
       if (GetContainer(userId, out int i).Add(userId))
            Console.WriteLine("容器" + i + " 用户" + userId + "  发起请求");
       else
            Console.WriteLine("容器" + i + " 用户" + userId + "  被拦截");
  }

接下去就是容器Container的代码了。

此地,对容器的选型用线程安全的ConcurrentDictionary类。
  线程安全:当五个线程同时读写同一个共享元素的时候,就会油不过生数量错乱,迭代报错等安全问提
  ConcurrentDictionary:除了GetOrAdd方法要慎用外,是.Net4.0专为解决Dictionary线程安全而出的新类型
  ReaderWriterLockSlim:较ReaderWriterLock优化的读写锁,多个线程同时做客读锁
或  一个线程访问写锁

private ReaderWriterLockSlim obj = new ReaderWriterLockSlim();  //在每个容器中申明一个读写锁
public ConcurrentDictionary<string, ConcurrentList<DateTime>> dic = new ConcurrentDictionary<string, ConcurrentList<DateTime>>(); //创建该容器 dic

接下来当您向容器添加一条管道中的数据是透过这么些办法:

 public bool Add(int userId)
 {
     obj.EnterReadLock();//挂读锁,允许多个线程同时写入该方法
     try
     {
         ConcurrentList<DateTime> dtList = dic.GetOrAdd(userId.ToString(),t=>{ new ConcurrentList<DateTime>()}); //如果不存在就新建 ConcurrentList
         return dtList.CounterAdd(10, DateTime.Now); //管道容量10,当临界管道容量后 返回false
     }
     finally
     {
         obj.ExitReadLock();
     }
 }

 那里,为了在后面的线程遍历删除ConcurrentList的管道的时候保证ConcurrentList的安全性,所以这里要加读锁。

 而ConcurrentList,因为.Net没有生产List集合类的线程安全(此地我表明下:之所以不用ConcurrentBag是因为要保管count和add的一致性,那里补充一下),所以自己新建了一个继续于List<T>的平安项目,在此间
封装了3个需要接纳的不二法门。

public class ConcurrentList<T> : List<T>
{
    private object obj = new object();

    public bool CounterAdd(int num, T value)
    {
        lock (obj)
        {
            if (base.Count >= num)
                return false;
            else
                base.Add(value);
            return true;
        }
    }
    public new bool Remove(T value)
    {
        lock (obj)
        {
            base.Remove(value);
            return true;
        }
    }
    public new T[] ToArray() 
    {
        lock (obj)
        {
            return base.ToArray();
        }
    }
}

末段就是线程的周转形式:

 public void Run()
 {
     ThreadPool.QueueUserWorkItem(c =>
     {
         while (true)
         {
             if (dic.Count > 0)
             {
                 foreach (var item in dic.ToArray())
                 {
                     ConcurrentList<DateTime> list = item.Value;
                     foreach (DateTime dt in list.ToArray())   
                     {
                         if (DateTime.Now.AddSeconds(-3) > dt)
                         {
                             list.Remove(dt);
                             Console.WriteLine("容器" + seat + " 已删除用户" + item.Key + "管道中的一条数据");
                         }
                     }
                     if (list.Count == 0)
                     {
                         obj.EnterWriteLock();
                         try
                         {
                             if (list.Count == 0)
                             {
                                 if (dic.TryRemove(item.Key, out ConcurrentList<DateTime> i))
                                 { Console.WriteLine("容器" + seat + " 已清除用户" + item.Key + "的List管道"); }
                             }
                         }
                         finally
                         {
                             obj.ExitWriteLock();
                         }
                     }
                 }

             }
             else
             {
                 Thread.Sleep(100);
             }
         }
     }
   );
 }

最终,是功力图,一个是依照控制台的,还一个是基于Signalr的。

 葡京在线开户 6葡京在线开户 7

这五遍,本次课程和线下课程比较,对学科几乎完成了100%的材料改进。大家将线下收到的忠实问题逐项拆解,然后以18年来BBY成熟的构思格局举行周全解读后,以音频+图文的花样表现给我们。

分布式下Redis

下边介绍了一种频率限制的模子,分布式与单机相比较,无非就是载体不同,大家即便把这个容器的载体从程序上移植出来,来弄成一个单独的服务仍然直接借用Redis也是实惠的。

此处就介绍分布式情形下,Redis的实现。

不同于Asp.Net的多线程模型,大概因为Redis的各类类型的要素非凡粒度的操作造成各个加锁的繁杂,所以在网络请求处理这块Redis是单线程的,基于Redis的落实则因为单线程的来头在编码角度不用太多着想到与逻辑无关的问题。

  简单介绍下,Redis是一个内存数据库,这么些数据库属于非关系型数据库,它的概念不同于一般的我们体会的Mysql
Oracle
SqlServer关系型数据库,它没有Sql没有字段名没有表名这么些概念,它和HttpRun提姆e.Cache的概念差不多一样,首先从操作上属于键值对格局,就如
Cache[“键名”]
这样就能博拿到值类似,而且可以对各样Key设置过期策略,而Redis中的Key所对应的值并不是想存啥就存啥的,它帮忙五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及sorted
set(有序聚集)。

今天要说的是Sorted
set有序聚集,有序聚集相相比此外的汇聚类型的特殊点在于,使用有序聚集的时候还是能给插入的要素指定一个
积分score,我们把这几个积分score明白为排序列,它里面会对积分举办排序,积分允许再度,而一成不变聚集中的元素则是绝无仅有。

  依然一样的思绪,每当有用户访问的时候,都对该用户的
管道(有序聚集)中添加一个因素,然后设置该因素的积分为当下时刻。接着在程序中开个线程,来对管道中积分小于约定刻钟的因素举办清理。因为规定有序聚集中的元素只可以是唯一值,所以在赋值方面只假设满足uuid即可。

 葡京在线开户 8

那么用Redis来促成的代码这就是近乎那种:

葡京在线开户 9

经过using语法糖实现IDisposable而卷入的Redis分布式锁,然后中间正常的逻辑判断。

诸如此类的代码固然也能不辱使命功用,但不够自己。Redis是个基于内存的数据库,于性能而言,瓶颈在于网络
IO 上,与Get一回发出五回呼吁相比较,能无法透过一段脚本来实现多数逻辑吗?

有的,Redis支持 Lua脚本:
  Lua
是一种轻量小巧的脚本语言,用标准C语言编写并以源代码格局开放,
其计划目的是为着放置应用程序中,从而为应用程序提供灵活的恢宏和定制功用。
  大致意思就是,直接向Redis发送一段脚本或者让它一贯本地读取一段脚本从而直接实现所有的逻辑。

/// <summary>
/// 如果 大于10(AccountNum) 就返回1   否则就增加一条集合中的元素 并返回 空
/// </summary>
/// <param name="zcardKey"></param>
/// <param name="score"></param>
/// <param name="zcardValue"></param>
/// <param name="AccountNum"></param>
/// <returns></returns>
public string LuaAddAccoundSorted(string zcardKey, double score, string zcardValue, int AccountNum)
{
    string str = "local uu = redis.call('zcard',@zcardKey) if (uu >=tonumber(@AccountNum)) then return 1 else redis.call('zadd',@zcardKey,@score,@zcardValue)  end";
    var re = _instance.GetDatabase(_num).ScriptEvaluate(LuaScript.Prepare(str), new { zcardKey = zcardKey, score = score, zcardValue = zcardValue, AccountNum=AccountNum });
    return re.ToString();
}

local
uu就是发明一个为名uu的变量的情趣,redis.call就是redis命令,那段脚本意思就是倘使大于10(AccountNum) 就重返1   否则就扩大一条集合中的元素 并赶回 空。

管道内元素处理的办法就是:

 /// <summary>
 /// 遍历当前所有前缀的有序集合,如果数量为0,那么就返回1 否则 就删除 满足最大分值条件区间的元素,如果该集合个数为0则消失
 /// </summary>
 /// <param name="zcardPrefix"></param>
 /// <param name="score"></param>
 /// <returns></returns>
public string LuaForeachRemove(string zcardPrefix, double score)
 {
     StringBuilder str = new StringBuilder();
     str.Append("local uu = redis.call('keys',@zcardPrefix) "); //声明一个变量 去获取 模糊查询的结果集合
     str.Append("if(#uu==0) then");    //如果集合长度=0
     str.Append("   return 1 ");
     str.Append("else ");
     str.Append("   for i=1,#uu do ");   //遍历
     str.Append("       redis.call('ZREMRANGEBYSCORE',uu[i],0,@score) ");  //删除从0 到 该score 积分区间的元素
     str.Append("       if(redis.call('zcard',uu[i])==0) then ");  //如果管道长度=0
     str.Append("           redis.call('del',uu[i]) ");   //删除
     str.Append("       end ");
     str.Append("   end ");
     str.Append("end ");
     var re = _instance.GetDatabase(_num).ScriptEvaluate(LuaScript.Prepare(str.ToString()), new { zcardPrefix = zcardPrefix + "*", score = score });
     return re.ToString();

这2段代码通过发送Lua脚本的款式来形成了上上下下经过,因为Redis的网络模型原因,所以把LuaForeachRemove方法给提议来做个劳务来单独处理即可。至于这种多容器多线程的实现,则一心可以开七个Redis的实例来贯彻。最终放上效果图。

葡京在线开户 10

末段,我把这多少个都给做成了个Demo。可是尚未找到确切的上传网盘,所以大家可以留邮箱(留了就发),或者直接加QQ群文件自取,商量交换:166843154

 

我欢喜和我同样的人交朋友,不被环境影响,自己是和谐的教职工,欢迎加群
.Net web沟通群, QQ群:166843154 欲望与挣扎

 

作者:小曾
出处:http://www.cnblogs.com/1996V/p/8127576.html 欢迎转载,但任何转载必须保留完整文章及博客园出处,在显要地方显示署名以及原文链接。
.Net交流群, QQ群:166843154 欲望与挣扎 

这或许会是你见过最具有实操性和最富有收听价值的差事提议,同时也是对业余时间最值得的五遍投资。


24节课带你打破思想局限

每期8-10分钟,每一周两期,持续一个季度,每期至少为听众打破一个事情困局——这是生意小课堂在未来多个月里的“课程表”。

咱俩信任,这会是一个集年轻活泼与严穆严格于寥寥,能冲破你原有思想局限的差事思考类节目。

名叫冲破思想局限呢?其中一些,就是打破你对一部分事物的固有认知,刻板影像,从而找到解决问题的新角度。

举个例子,很多学生会来问我们那样一个题材,“我觉着自己的脾气太内向,怎么改?”

内向者总会本能地觉得自己的心性导致自己联系少,社交能力差,进而导致工作中的各种不顺。不过一个人的人性变异来源方方面面:遗传、环境、教育、实践经历,几乎是不可逆的。

你要做的不是一点一滴否定自己的内向性格,而是应该接受它,并发掘出内向性格的优势,并加以运用。比如内向者由于自己的灵巧,相较外向者会更有同理心,做事也会相对更细致,这么些同样是办事中很重点的人头。

基于上述这些题材,我们的教程所做的就是扩充你对于人性认知的角度,比方说,我们该从哪些角度去体会。然后可以越来越合理的去看待你的这么些性格,并找到符合她的迈入的一个势头和条件。

*
*


俺们想跟你聊的刀刀见血

有关职业问题,无外乎这几类,“认知我”,“认知工作”,“映现自己”。

大家会以真实的用户问题为切入点,辅导用户看到这么些题目背后的法则,以及可以更进一步考虑和行进的角度。

下边,是我们的教程中会涉及到的一部分话题,咱们可以看看是不是戳中了自己。

咀嚼自我类

1. 什么才能断定自己喜欢做哪些?

2. 性格内向,怎么调整?

3. 职业性格测评靠谱么?到底怎么用?

4. 找不到祥和的优势是怎样,怎么做?

认知工作类

1. 一贯不时间实习怎么办?用人单位除了实习更注重什么?

2. 我们都说找工作要贯彻价值,不过本人就觉着钱最实际,有问题么?

3. 我妈希望自己考公务员,但是本人还想看看另外,怎么平衡走路?

4. 怎么在实习的时候争取到被留用的时机?

展现自我类

1. 就业压力大,通过各个网申和面试后依旧被挂,要咋做?

2. 怎么着写出高水准的简历?

3. 无领导小组群面咋样才能脱颖而出?(群面能力该怎样自身培训)

4. 怎么样和店铺谈工资及升华?

有关上述提到的那些问题,我们会以全新的角度来为你解读,力求让你立竿见影地感受到原来认知的紧缺,并给到你实际可用的实操提出。

这边,有一部分经验过BBY思维的职业班学员,对于上述问题重新认识后,找到当下困境破局之法的案例,有趣味的话,你可以看看:

不容考研,我的确进了提问集团!工科生跨行求职小目的变现记

学了四年园艺工程,终于投奔文学工作:那个已经的不明与选取

实习多少个月,从手忙脚乱到一天成功“一周”任务量

变形记:从复旦“果农”研究生到埃森哲consultant


听了这课真的有用吗?

BeBeyond的教程一直立足于从思想情势上,对人展开指点和改动,也由此往往能在短期内,让学生摆脱那些过去的友善,急忙打开新观点去对待自己要走的路。

去盼望遇见最棒的特别自己

下边,整理的BBY1十一月职业班同学,在攻读课程后的体会,真实无添加,请大家一起来倾听一下。

全部经过中有种抓住痛点,然后在逐年解决的感觉到,上完课心境特其它舒服。比如平日不欣赏说话,通过那多少个课有意识去找话说;我前边有点不自信,感觉通过队友的评头品足,渐渐有了一部分满怀信心。

我明白了,要放手去做,去执行,不要想太多。不欣赏说话,就要去说,去制伏心境障碍。不擅长交朋友,就尝试交不同的情人,显而易见就是去做。

——by L同学

当自己被单独女博导折磨的心灵很有怨气(我不想自己要好成为一个有怨气的人,总以为怨气会腐蚀人心),做事很消沉的时候,在这短暂时间内所学到的东西,让自家心坎宁静了许多。

譬如“时时刻刻都在锻练自己,要是能和任何人合作,那么友好的门道,能力,事业都会变得很达观……”,那个话会让自身想通了很多工作,会安抚自己,平和地去和我导相处,我期望我会时时刻刻念着这几句话,友善可亲地对待我先生,直至顺利毕业。

在有了怎么是职业人,什么是自然人的回味后,我跟单身女博导的涉嫌转移了,我初始积极向本人的名师互换,结果我的名师对本人的态度也截然不一样了,本来还可能要延毕,现在不会了。

——by H同学


=====


课程介绍

学科设置

这是BeBeyond第一次将线下体验式Workshop的思维框架应用到及时我们最关注职业发展的题材上,并享受到线上平台。全期BeBeyond职业小课堂将有24节课,每礼拜天、礼拜三晚6点为大家准时播放。无限次回听。

学科格局

每一节职业小课堂将配以音频、文摘,以及线上社群,大家可以在社群中探究、分享对于工作的意见、疑惑、提出等。

交互情势

俺们每期会从许多线下的问询者中抽取被较多精晓的题目看作钻探的话题展开研讨,同时你在倾听之后,可以主动留言你的获取与疑惑,得到点赞最多的题目,也将改成研讨话题之一。

出席情势

俺们也会无线上社群,让您可以和重重的人开展在线商量,得到更多的角度与工作想法。

申请方法

此次的线上课程为BeBeyond与简书联合推出,课程将于简书平台发布,报名办法有两种:

1、在简书高校堂公众号后台回复“职场”

2、长按下图保存至微信打开:

3、点击黄色字体积分商城,使用积分举办采购。

在本篇推文下方,你还足以将您对此工作的疑惑,回复给到大家,复苏中点赞最高的题目,我们将专门做一期音频课程,举办科班的剖析

提出该问题的同学,还将免费获取我们的营生小课堂产品,所以,还等什么?赶快行动起来!