mg4155com > mg4155线路检测手机版 > 二十四线程编制程序系列,七年AliPython支出技术

原标题:二十四线程编制程序系列,七年AliPython支出技术

浏览次数:178 时间:2019-12-09

学习指标

1.8 使用Barrier类

Barrier类用于消灭一个那些难得的主题材料,寻平常常用不上。Barrier类调节生机勃勃雨后苦笋线程实行阶段性的竞相专门的学问。

若是以后相互工作分为2个品级,每种线程在成就它本身那有个别阶段1的行事后,必须停下来等待其余线程完毕阶段1的办事;等全数线程均达成阶段1专门的职业后,每种线程又发轫运转,完毕阶段2做事,等待其余线程全部完事阶段2办事后,整个工艺流程才甘休。

演示代码如下所示,该代码演示了四个线程分品级的实现职业。

static void Main(string[] args)
{
    var t1 = new Thread(() => PlayMusic("钢琴家", "演奏一首令人惊叹的独奏曲", 5));
    var t2 = new Thread(() => PlayMusic("歌手", "唱着他的歌", 2));

    t1.Start();
    t2.Start();

    Console.ReadLine();
}

static Barrier _barrier = new Barrier(2,
 Console.WriteLine($"第 {b.CurrentPhaseNumber + 1} 阶段结束"));

static void PlayMusic(string name, string message, int seconds)
{
    for (int i = 1; i < 3; i++)
    {
        Console.WriteLine("----------------------------------------------");
        Thread.Sleep(TimeSpan.FromSeconds(seconds));
        Console.WriteLine($"{name} 开始 {message}");
        Thread.Sleep(TimeSpan.FromSeconds(seconds));
        Console.WriteLine($"{name} 结束 {message}");
        _barrier.SignalAndWait();
    }
}

运营结果如下所示,当“艺人”线程达成后,并未立时截至,而是等待“钢琴大师”线程甘休,当"钢琴大师"线程截至后,才初阶第2阶段的行事。

mg4155 1

1.8 使用BackgroundWorker组件

本节最重要介绍BackgroundWorker组件的应用,该零部件实际上被用于Windows窗体应用程序(Windows Forms Application,简单的称呼WPF卡塔尔(قطر‎中,通过它完成的代码能够直接与UI控制器交互作用,特别自认和好用。

演示代码如下所示,使用BackgroundWorker来促成对数码举办测算,况兼让其帮忙报告专业进度,协理撤销职分。

static void Main(string[] args)
{
    var bw = new BackgroundWorker();
    // 设置可报告进度更新
    bw.WorkerReportsProgress = true;
    // 设置支持取消操作
    bw.WorkerSupportsCancellation = true;

    // 需要做的工作
    bw.DoWork += Worker_DoWork;
    // 工作处理进度
    bw.ProgressChanged += Worker_ProgressChanged;
    // 工作完成后处理函数
    bw.RunWorkerCompleted += Worker_Completed;

    bw.RunWorkerAsync();

    WriteLine("按下 `C` 键 取消工作");
    do
    {
        if (ReadKey(true).KeyChar == 'C')
        {
            bw.CancelAsync();
        }

    }
    while (bw.IsBusy);
}

static void Worker_DoWork(object sender, DoWorkEventArgs e)
{
    WriteLine($"DoWork 线程池 线程 id: {CurrentThread.ManagedThreadId}");
    var bw = (BackgroundWorker)sender;
    for (int i = 1; i <= 100; i++)
    {
        if (bw.CancellationPending)
        {
            e.Cancel = true;
            return;
        }
        if (i % 10 == 0)
        {
            bw.ReportProgress(i);
        }

        Sleep(TimeSpan.FromSeconds(0.1));
    }

    e.Result = 42;
}

static void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    WriteLine($"已完成{e.ProgressPercentage}%. " +
              $"处理线程 id: {CurrentThread.ManagedThreadId}");
}

static void Worker_Completed(object sender, RunWorkerCompletedEventArgs e)
{
    WriteLine($"完成线程池线程 id: {CurrentThread.ManagedThreadId}");
    if (e.Error != null)
    {
        WriteLine($"异常 {e.Error.Message} 发生.");
    }
    else if (e.Cancelled)
    {
        WriteLine($"操作已被取消.");
    }
    else
    {
        WriteLine($"答案是 : {e.Result}");
    }
}

运维结果如下所示。

mg4155 2

在本节中,使用了C#中的别的一个语法,叫事件(event)。当然这里的平地风波分歧于早前在线程同步章节中提到的事件,这里是观看者设计方式的体现,包括事件源、订阅者和事件管理程序。由此,除了异步APM格局意外,还应该有根据事件的异步情势(Event-based Asynchronous Pattern,简称 EAP卡塔尔(英语:State of Qatar)

cs文件事件如下:

                      微分销设置

mg4155 3

  1. 左右Python底工有关的学问
  2. 为后续的上学打下牢固的底子

1.7 使用CountDownEvent类

CountDownEvent类内部组织选择了多个ManualResetEventSlim对象。那么些布局阻塞一个线程,直到它在那之中流量计(CurrentCount)变为0时,才裁撤梗塞。也便是说它并不是掣肘对已经恐慌的能源池的拜谒,而是唯有当计数为0时才同意访问。

此间须求注意的是,当CurrentCount变为0时,那么它就不可能被转移了。为0以后,Wait()措施的窒碍被免去。

演示代码如下所示,独有当Signal()主意被调用2次随后,Wait()艺术的围堵才被消弭。

static void Main(string[] args)
{
    Console.WriteLine($"开始两个操作  {DateTime.Now.ToString("mm:ss.ffff")}");
    var t1 = new Thread(() => PerformOperation("操作 1 完成!", 4));
    var t2 = new Thread(() => PerformOperation("操作 2 完成!", 8));
    t1.Start();
    t2.Start();

    // 等待操作完成
    _countdown.Wait();
    Console.WriteLine($"所有操作都完成  {DateTime.Now.ToString("mm: ss.ffff")}");
    _countdown.Dispose();

    Console.ReadLine();
}

// 构造函数的参数为2 表示只有调用了两次 Signal方法 CurrentCount 为 0时  Wait的阻塞才解除
static CountdownEvent _countdown = new CountdownEvent(2);

static void PerformOperation(string message, int seconds)
{
    Thread.Sleep(TimeSpan.FromSeconds(seconds));
    Console.WriteLine($"{message}  {DateTime.Now.ToString("mm:ss.ffff")}");

    // CurrentCount 递减 1
    _countdown.Signal();
}

运维结果如下图所示,可以预知唯有当操作1和操作2都成功之后,才执行输出全部操作都产生。

mg4155 4

1.2 在线程池中调用委托

本节展现的是如何在线程池中怎么着异步的履行委托,然后将介绍叁个叫异步编制程序模型(Asynchronous Programming Model,简单的称呼APM卡塔尔国的异步编制程序方式。

在本节及其后,为了收缩代码量,在援用程序集注脚地方暗中同意增多了using static System.Consoleusing static System.Threading.Thead宣称,这样证明能够让大家在程序中少许一些意义十分小的调用语句。

以身作则代码如下所示,使用了常备创造线程和APM形式来实行同二个义务。

static void Main(string[] args)
{
    int threadId = 0;

    RunOnThreadPool poolDelegate = Test;

    var t = new Thread(() => Test(out threadId));
    t.Start();
    t.Join();

    WriteLine($"手动创建线程 Id: {threadId}");

    // 使用APM方式 进行异步调用  异步调用会使用线程池中的线程
    IAsyncResult r = poolDelegate.BeginInvoke(out threadId, Callback, "委托异步调用");
    r.AsyncWaitHandle.WaitOne();

    // 获取异步调用结果
    string result = poolDelegate.EndInvoke(out threadId, r);

    WriteLine($"Thread - 线程池工作线程Id: {threadId}");
    WriteLine(result);

    Console.ReadLine();
}

// 创建带一个参数的委托类型
private delegate string RunOnThreadPool(out int threadId);

private static void Callback(IAsyncResult ar)
{
    WriteLine("Callback - 开始运行Callback...");
    WriteLine($"Callback - 回调传递状态: {ar.AsyncState}");
    WriteLine($"Callback - 是否为线程池线程: {CurrentThread.IsThreadPoolThread}");
    WriteLine($"Callback - 线程池工作线程Id: {CurrentThread.ManagedThreadId}");
}

private static string Test(out int threadId)
{
    string isThreadPoolThread = CurrentThread.IsThreadPoolThread ? "ThreadPool - ": "Thread - ";

    WriteLine($"{isThreadPoolThread}开始运行...");
    WriteLine($"{isThreadPoolThread}是否为线程池线程: {CurrentThread.IsThreadPoolThread}");
    Sleep(TimeSpan.FromSeconds(2));
    threadId = CurrentThread.ManagedThreadId;
    return $"{isThreadPoolThread}线程池工作线程Id: {threadId}";
}

运维结果如下图所示,此中以Thread起始的为手动成立的线程输出的音讯,而TheadPool为始发线程池职责输出的消息,Callback为APM方式运作职分达成后,实践的回调方法,能够清楚的看到,Callback的线程也是线程池的劳作线程。

mg4155 5

在上文中,使用BeginOperationName/EndOperationName方法和.Net中的IAsyncResult对象的办法被叫作异步编制程序模型(或APM形式卡塔尔(英语:State of Qatar),那样的点子被称作异步方法。使用委托的BeginInvoke主意来运维该信托,BeginInvoke接过多个回调函数,该回调函数会在职分管理完了后背调用,况兼能够传递一个顾客自定义的景况给回调函数。

明天这种APM编制程序方式用的更加少了,更推荐应用职责并行库(Task Parallel Library,简单的称呼TPL卡塔尔(قطر‎来集团异步API。

我对C#的认知。

     后台核查

mg4155 6

mg4155 7

目录

小编水平有限,如若不当款待各位商议指正!

但RoutedEventHandler特别之处是,他的sender并不一定是实际的源,因为他是三个冒泡路由事件,即上涨事件。

二、分销原理

接续后代厂家或品牌集团根据商家Wechat服务号上配备微分销商店,职员和工人和代理商在集团的Wechat分销市肆基本功上生成专门项目于自身的四个供应商号(工作者与承包商即二级承包商),职员和工人的意中人也许中间商的客商在工作者或中间商的民用微信百货店幼功上海重机厂复生成个人代理商城(朋友与客商即三级代理商),进而达成集团零资金泛员工业态。

分销形式:全体公民分销、门路分销

Python网络爬虫



e:代表事件参数,即触发该事件后,事件为被触发的信托,传递了有的参数,以利于委托在处理数量时,更简便易行。

                     推广码

5.2、后台管理

mg4155 8

 

1.2 施行基本原子操作

CLKuga保险了对那些数据类型的读写是原子性的:Boolean、Char、(S)Byte、(U)Int16、(U)Int32、(U)IntPtr和Single。可是只要读写Int64兴许会发出读取撕裂(torn read卡塔尔(英语:State of Qatar)的难题,因为在三十个人操作系统中,它必要实践五次Mov操作,无法在二个年华内施行到位。

那么在本节中,就能首要的牵线System.Threading.Interlocked类提供的艺术,Interlocked类中的每个方法都是进行贰遍的读取以至写入操作。越多与Interlocked类相关的材质请参见链接,戳一戳.aspx卡塔尔(قطر‎本文不在赘述。

示范代码如下所示,分别使用了两种方法开展计数:错误计数形式、lock锁情势和Interlocked原子形式。

private static void Main(string[] args)
{
    Console.WriteLine("错误的计数");

    var c = new Counter();
    Execute(c);

    Console.WriteLine("--------------------------");


    Console.WriteLine("正确的计数 - 有锁");

    var c2 = new CounterWithLock();
    Execute(c2);

    Console.WriteLine("--------------------------");


    Console.WriteLine("正确的计数 - 无锁");

    var c3 = new CounterNoLock();
    Execute(c3);

    Console.ReadLine();
}

static void Execute(CounterBase c)
{
    // 统计耗时
    var sw = new Stopwatch();
    sw.Start();

    var t1 = new Thread(() => TestCounter(c));
    var t2 = new Thread(() => TestCounter(c));
    var t3 = new Thread(() => TestCounter(c));
    t1.Start();
    t2.Start();
    t3.Start();
    t1.Join();
    t2.Join();
    t3.Join();

    sw.Stop();
    Console.WriteLine($"Total count: {c.Count} Time:{sw.ElapsedMilliseconds} ms");
}

static void TestCounter(CounterBase c)
{
    for (int i = 0; i < 100000; i++)
    {
        c.Increment();
        c.Decrement();
    }
}

class Counter : CounterBase
{
    public override void Increment()
    {
        _count++;
    }

    public override void Decrement()
    {
        _count--;
    }
}

class CounterNoLock : CounterBase
{
    public override void Increment()
    {
        // 使用Interlocked执行原子操作
        Interlocked.Increment(ref _count);
    }

    public override void Decrement()
    {
        Interlocked.Decrement(ref _count);
    }
}

class CounterWithLock : CounterBase
{
    private readonly object _syncRoot = new Object();

    public override void Increment()
    {
        // 使用Lock关键字 锁定私有变量
        lock (_syncRoot)
        {
            // 同步块
            Count++;
        }
    }

    public override void Decrement()
    {
        lock (_syncRoot)
        {
            Count--;
        }
    }
}


abstract class CounterBase
{
    protected int _count;

    public int Count
    {
        get
        {
            return _count;
        }
        set
        {
            _count = value;
        }
    }

    public abstract void Increment();

    public abstract void Decrement();
}

运维结果如下所示,与预期结果基本契合。

mg4155 9

  • 1.1 简介
  • 1.2 在线程池中调用委托
  • 1.3 向线程池中归入异步操作
  • 1.4 线程池与并行度
  • 1.5 达成多少个撤回选项
  • 1.6 在线程池中采纳等待事件微电脑及逾期
  • 1.7 使用机械漏刻
  • 1.8 使用BackgroundWorker组件
  • 参谋书籍
  • 我水平有限,纵然不当迎接各位评论指正!
public void Init()
{   
    testEvent += new TestDelegate(EventSyntax_testEvent); 
    testEvent += EventSyntax_testEvent; 
}
private void EventSyntax_testEvent(string message)
{
    Console.WriteLine(message);
}

                       商品分销价格配置

mg4155 10

*6 - *** 网址开荒:凭借django,flask框架自个儿搭建网址。

笔者水平有限,假若不当款待各位议论指正!

1.7 使用放大计时器

放大计时器是FCL提供的叁个类,叫System.Threading.Timer,可要结果与成立周期性的异步操作。该类应用比较轻便。

以下的演示代码应用了电磁打点计时器,并安装了沙漏延时运维时间和周期时间。

static void Main(string[] args)
{
    WriteLine("按下回车键,结束定时器...");
    DateTime start = DateTime.Now;

    // 创建定时器
    _timer = new Timer(_ => TimerOperation(start), null
        , TimeSpan.FromSeconds(1)
        , TimeSpan.FromSeconds(2));
    try
    {
        Sleep(TimeSpan.FromSeconds(6));

        _timer.Change(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(4));

        ReadLine();
    }
    finally
    {
        //实现了IDispose接口  要及时释放
        _timer.Dispose();
    }
}

static Timer _timer;

static void TimerOperation(DateTime start)
{
    TimeSpan elapsed = DateTime.Now - start;
    WriteLine($"离 {start} 过去了 {elapsed.Seconds} 秒. " +
              $"定时器线程池 线程 id: {CurrentThread.ManagedThreadId}");
}

运作结果如下所示,可见反应计时器根据所设置的周期时间循环的调用TimerOperation()方法。

mg4155 11

其间最经典的就是伊夫ntHandler和Routed伊芙ntHandler。

     订单返佣实际情况

 

Python WEB开发

1.10 使用SpinWait类

SpinWait是二个常用的混合情势的类,它被规划成采纳顾客情势等待生龙活虎段时间,人后切换至基本格局以节省CPU时间。

它的选取特别轻巧,演示代码如下所示。

static void Main(string[] args)
{
    var t1 = new Thread(UserModeWait);
    var t2 = new Thread(HybridSpinWait);

    Console.WriteLine("运行在用户模式下");
    t1.Start();
    Thread.Sleep(20);
    _isCompleted = true;
    Thread.Sleep(TimeSpan.FromSeconds(1));
    _isCompleted = false;

    Console.WriteLine("运行在混合模式下");
    t2.Start();
    Thread.Sleep(5);
    _isCompleted = true;

    Console.ReadLine();
}

static volatile bool _isCompleted = false;

static void UserModeWait()
{
    while (!_isCompleted)
    {
        Console.Write(".");
    }
    Console.WriteLine();
    Console.WriteLine("等待结束");
}

static void HybridSpinWait()
{
    var w = new SpinWait();
    while (!_isCompleted)
    {
        w.SpinOnce();
        Console.WriteLine(w.NextSpinWillYield);
    }
    Console.WriteLine("等待结束");
}

运作结果如下两图所示,首先程序运转在模仿的客户情势下,使CPU有七个短命的峰值。然后接受SpinWait做事在混合情势下,首先标识变量为False高居客商方式自旋中,等待未来步入底蕴模式。

mg4155 12

mg4155 13

1.5 完结三个注销选项

在头里的稿子中有关联,要是需求截至八个线程的施行,那么能够采纳Abort()艺术,可是有过多的缘故并不引入应用Abort()方法。

此间推荐的主意是运用协作式打消(cooperative cancellation卡塔尔(قطر‎,那是生机勃勃种保险的技巧来安全废除不再须求的天职。其利害攸关接受CancellationTokenSourceCancellationToken多个类,具体用法见上面演示代码。

以下延时期码重如果兑现了接收CancellationTokenCancellationTokenSource来促成职责的吊销。不过职分撤除后能够张开二种操作,分别是:直接回到、抛出ThrowIfCancellationRequesed相当和实施回调。详细请看代码。

static void Main(string[] args)
{
    // 使用CancellationToken来取消任务  取消任务直接返回
    using (var cts = new CancellationTokenSource())
    {
        CancellationToken token = cts.Token;
        ThreadPool.QueueUserWorkItem(_ => AsyncOperation1(token));
        Sleep(TimeSpan.FromSeconds(2));
        cts.Cancel();
    }

    // 取消任务 抛出 ThrowIfCancellationRequesed 异常
    using (var cts = new CancellationTokenSource())
    {
        CancellationToken token = cts.Token;
        ThreadPool.QueueUserWorkItem(_ => AsyncOperation2(token));
        Sleep(TimeSpan.FromSeconds(2));
        cts.Cancel();
    }

    // 取消任务 并 执行取消后的回调函数
    using (var cts = new CancellationTokenSource())
    {
        CancellationToken token = cts.Token;
        token.Register(() => { WriteLine("第三个任务被取消,执行回调函数。"); });
        ThreadPool.QueueUserWorkItem(_ => AsyncOperation3(token));
        Sleep(TimeSpan.FromSeconds(2));
        cts.Cancel();
    }

    ReadLine();
}

static void AsyncOperation1(CancellationToken token)
{
    WriteLine("启动第一个任务.");
    for (int i = 0; i < 5; i++)
    {
        if (token.IsCancellationRequested)
        {
            WriteLine("第一个任务被取消.");
            return;
        }
        Sleep(TimeSpan.FromSeconds(1));
    }
    WriteLine("第一个任务运行完成.");
}

static void AsyncOperation2(CancellationToken token)
{
    try
    {
        WriteLine("启动第二个任务.");

        for (int i = 0; i < 5; i++)
        {
            token.ThrowIfCancellationRequested();
            Sleep(TimeSpan.FromSeconds(1));
        }
        WriteLine("第二个任务运行完成.");
    }
    catch (OperationCanceledException)
    {
        WriteLine("第二个任务被取消.");
    }
}

static void AsyncOperation3(CancellationToken token)
{
    WriteLine("启动第三个任务.");
    for (int i = 0; i < 5; i++)
    {
        if (token.IsCancellationRequested)
        {
            WriteLine("第三个任务被取消.");
            return;
        }
        Sleep(TimeSpan.FromSeconds(1));
    }
    WriteLine("第三个任务运行完成.");
}

运行结果如下所示,切合预期结果。

mg4155 14

大家率先在XAML页面定义一个RadioButton按键,然后设置他的模板是Button。然后分别定义各自的Click方法。

四、生机勃勃期兑现的效应(现阶段)

 4.1、PC后端

1、增添路子管理;
2、增添返佣清单;
3、改善订单详细情况,增添返佣详细情况;
4、加多查看下级功用;
5、加多核查门路人士入口;
6、后台提供改价效用(消除一些地带有特别打折的风貌)
7、撤除返佣是依据特点价格(比方扣除评测中央部分)
8、微主页扩大“笔者的分销Url” {{#DCCenterUrl}}标签

4.2、微信端:
1、扩大“笔者的分销”页面:完结分销相关的音讯呈现和输入(作者的返佣、作者的部属、推广海报、我的推广码、)
2、增添“小编的返佣”页面;
3、扩张“小编的下边”页面;

 

对Python开垦技巧感兴趣的同窗,迎接加QQ群:705673780,一同读书,相互商量。


1.4 线程池与并行度

在本节中,主要是应用普通创设线程和使用线程池内的线程在职责量十分大的场合下有啥分化,大家模拟了三个情形,创制了累累不等的线程,然后分别选拔普通成立线程格局和线程池格局看看有啥样两样。

static void Main(string[] args)
{
    const int numberOfOperations = 500;
    var sw = new Stopwatch();
    sw.Start();
    UseThreads(numberOfOperations);
    sw.Stop();
    WriteLine($"使用线程执行总用时: {sw.ElapsedMilliseconds}");

    sw.Reset();
    sw.Start();
    UseThreadPool(numberOfOperations);
    sw.Stop();
    WriteLine($"使用线程池执行总用时: {sw.ElapsedMilliseconds}");

    Console.ReadLine();
}

static void UseThreads(int numberOfOperations)
{
    using (var countdown = new CountdownEvent(numberOfOperations))
    {
        WriteLine("通过创建线程调度工作");
        for (int i = 0; i < numberOfOperations; i++)
        {
            var thread = new Thread(() =>
            {
                Write($"{CurrentThread.ManagedThreadId},");
                Sleep(TimeSpan.FromSeconds(0.1));
                countdown.Signal();
            });
            thread.Start();
        }
        countdown.Wait();
        WriteLine();
    }
}

static void UseThreadPool(int numberOfOperations)
{
    using (var countdown = new CountdownEvent(numberOfOperations))
    {
        WriteLine("使用线程池开始工作");
        for (int i = 0; i < numberOfOperations; i++)
        {
            ThreadPool.QueueUserWorkItem(_ =>
            {
                Write($"{CurrentThread.ManagedThreadId},");
                Sleep(TimeSpan.FromSeconds(0.1));
                countdown.Signal();
            });
        }
        countdown.Wait();
        WriteLine();
    }
}

实践结果如下,可以预知使用原本的创办线程施行,速度特别快。只花了2秒钟,不过创设了500两个线程,而使用线程池绝对来讲一点也不慢,花了9分钟,可是只创设了相当少的线程,为操作系统节省了线程和内部存款和储蓄器空间,但花了更加多的日子。

mg4155 15

出于事件必得[标记响应措施的委托],所以那些事件所选取的委托都有叁个联袂的性状,命名中隐含Event。

三、功用规划设计

mg4155 16 

3.1、微分销首页

首页要求表达:

  1. 轮播、头条
  2. 导航栏有:预定、培养演习、合伙人基本。
    “预定”跳转至前些时间底步列表页;
    “培养练习”跳转到全数开班列表页;
    “合伙人基本”点击后,决断该帐号是或不是已经申请成为协同人,固然,则直接步入合伙人基本,若否,则先出示合伙人表达页,点击“申请成为协同人”后,步向合伙人申请页。
    3.商品推荐栏,图片+商品链接。在后台处理体系中,扩大有关爱护商品推荐栏的作用。以UI设计的图纸数量为准。

mg4155 17

3.2、申请成为大器晚成道人

一流分销员方式:客商扫描分销员的二维码,关切大伙儿号后,自动形成分销员的观者。

二级分销员格局:客商扫描分销员的二维码,关注民众号后,自动推送一条图文音信(申请参预二级分销员的链接),

顾客若申请,自动成为分销员的客官和其属下分销员;
若客户不申请,只造成分销员的客官。

分销员离职后,公司有权在后台停用其分销员身份;停用后该分销员不再显得分销中央入口,不再享受业绩酬金。

mg4155 18

3.3、排行榜

供给表达

1.个体大旨页面排行榜数据暗中同意展现月度受益排名,

跻身排行的榜单页面暗许展现后日入账排名

2.私家基本和自个儿的观众列表的多寡实时更新
排名榜数据次日更新

3.名词解释:
日收入:展现即日到账的低收入
周收益:显示近来7天的收入
月工资:彰显当前月的入账(不分包前日,前天数据明天手艺总括显示)
总纯收入:历史发生的具有收入

日观者:前些天新扩充的观众数量
月观者:上个月大幅度增涨的观者数量
总客官:历史的兼具客官数量

4.排名的榜单逻辑:
①业绩为0的不上榜

②叁个榜单最多呈现前30名排名数据(暂定,数据可布署)
若某天唯有5名分销员有功绩,只展现5名分销员的排名

③多少人日受益数据生机勃勃致,并列排名。
如,a排行第生机勃勃,b和c并列排行第二,d排行第5

b和c的排列顺序根据那四个人的注册顺排序(ID),
首先登场记的排在上面

5.排名的榜单前3的所属饭店暗中同意展现7个字,若展现不下,用...替代

6.排名的榜单中个人所属旅社和机关做叁个开关,能够采取前面一个人展览示或许不展现

mg4155 19

 

mg4155 20 

1.6 使用ManualResetEventSlim类

ManualResetEventSlim使用和ManualResetEvent类基本后生可畏致,只是ManualResetEventSlim工作在混合形式下,而它与AutoResetEventSlim分裂的地点就是索要手动重新初始化事件,约等于调用Reset()技巧将事件重新设置为false

示范代码如下,形象的将ManualResetEventSlim打比如成大门,当事件为true时大门展开,线程毁灭堵塞;而事件为false时大门关闭,线程拥塞。

static void Main(string[] args)
        {
            var t1 = new Thread(() => TravelThroughGates("Thread 1", 5));
            var t2 = new Thread(() => TravelThroughGates("Thread 2", 6));
            var t3 = new Thread(() => TravelThroughGates("Thread 3", 12));
            t1.Start();
            t2.Start();
            t3.Start();

            // 休眠6秒钟  只有Thread 1小于 6秒钟,所以事件重置时 Thread 1 肯定能进入大门  而 Thread 2 可能可以进入大门
            Thread.Sleep(TimeSpan.FromSeconds(6));
            Console.WriteLine($"大门现在打开了!  时间:{DateTime.Now.ToString("mm:ss.ffff")}");
            _mainEvent.Set();

            // 休眠2秒钟 此时 Thread 2 肯定可以进入大门
            Thread.Sleep(TimeSpan.FromSeconds(2));
            _mainEvent.Reset();
            Console.WriteLine($"大门现在关闭了! 时间:{DateTime.Now.ToString("mm: ss.ffff")}");

            // 休眠10秒钟 Thread 3 可以进入大门
            Thread.Sleep(TimeSpan.FromSeconds(10));
            Console.WriteLine($"大门现在第二次打开! 时间:{DateTime.Now.ToString("mm: ss.ffff")}");
            _mainEvent.Set();
            Thread.Sleep(TimeSpan.FromSeconds(2));

            Console.WriteLine($"大门现在关闭了! 时间:{DateTime.Now.ToString("mm: ss.ffff")}");
            _mainEvent.Reset();

            Console.ReadLine();
        }

        static void TravelThroughGates(string threadName, int seconds)
        {
            Console.WriteLine($"{threadName} 进入睡眠 时间:{DateTime.Now.ToString("mm:ss.ffff")}");
            Thread.Sleep(TimeSpan.FromSeconds(seconds));

            Console.WriteLine($"{threadName} 等待大门打开! 时间:{DateTime.Now.ToString("mm:ss.ffff")}");
            _mainEvent.Wait();

            Console.WriteLine($"{threadName} 进入大门! 时间:{DateTime.Now.ToString("mm:ss.ffff")}");
        }

        static ManualResetEventSlim _mainEvent = new ManualResetEventSlim(false);

运转结果如下,与预期结果切合。

mg4155 21

1.3 向线程池中纳入异步操作

本节将介绍怎么样将异步操作放入线程池中实行,况兼如何传递参数给线程池中的线程。本节中首要性行使的是ThreadPool.QueueUserWorkItem()办法,该方法可将急需周转的职分通过信托的样式传递给线程池中的线程,并且同意传递参数。

行使比较简单,演示代码如下所示。演示了线程池使用中怎么着传递格局和参数,末了索要注意的是选用了Lambda表明式和它的闭包机制。

static void Main(string[] args)
{
    const int x = 1;
    const int y = 2;
    const string lambdaState = "lambda state 2";

    // 直接将方法传递给线程池
    ThreadPool.QueueUserWorkItem(AsyncOperation);
    Sleep(TimeSpan.FromSeconds(1));

    // 直接将方法传递给线程池 并且 通过state传递参数
    ThreadPool.QueueUserWorkItem(AsyncOperation, "async state");
    Sleep(TimeSpan.FromSeconds(1));

    // 使用Lambda表达式将任务传递给线程池 并且通过 state传递参数
    ThreadPool.QueueUserWorkItem(state =>
    {
        WriteLine($"Operation state: {state}");
        WriteLine($"工作线程 id: {CurrentThread.ManagedThreadId}");
        Sleep(TimeSpan.FromSeconds(2));
    }, "lambda state");

    // 使用Lambda表达式将任务传递给线程池 通过 **闭包** 机制传递参数
    ThreadPool.QueueUserWorkItem(_ =>
    {
        WriteLine($"Operation state: {x + y}, {lambdaState}");
        WriteLine($"工作线程 id: {CurrentThread.ManagedThreadId}");
        Sleep(TimeSpan.FromSeconds(2));
    }, "lambda state");

    ReadLine();
}

private static void AsyncOperation(object state)
{
    WriteLine($"Operation state: {state ?? "(null)"}");
    WriteLine($"工作线程 id: {CurrentThread.ManagedThreadId}");
    Sleep(TimeSpan.FromSeconds(2));
}

运作结果如下图所示。

mg4155 22

[SerializableAttribute]
[ComVisibleAttribute(true)]
public delegate void EventHandler(
 object sender,
 EventArgs e
)

生龙活虎、微分销是什么样?

不管线下照旧线上,获客和流量都以高转变的前提。因而,为了消除那些标题,咱们推出了扁平式发展供应商,让越多的商户成为专营商,大幅减弱出卖基金。

 

微分销系统,让全部参与分享和松手的人都能成为受益者,让新会员、老会员、潜客、音信安全人士变为三个完好无损,产生高粘性的闭环。

微分销,是依据微信徒人平台上的二级分销市廛,是陪同着Wechat经营发售的抢手而兴起的大器晚成种互联网经营发卖格局。

微分销(即Wechat分销),在大额时期背景下公司数据经营发卖方式,是依据Wechat群众平台定制研究开发,特意为品牌厂家和厂家提供Wechat相关超级市场、微分销门路的二级分销Wechat商店种类,微分销助力公司高粘度、快速将自媒体转变为自有供应商。

  1. 调控Python机器学习与数据开掘、深度学习根基

    1. 学会用Python做多少处理
    2. 支配数据开采、机器学习与深度学习的基本知识点
    3. 浓重明白举不胜举机器学习与数量开掘算法的最底层原理,并透过Python达成
  2. 深刻掌握神经互连网与深度学习算法的最底层原理,并因而Python实现

  3. 在行使用深度学习的种种框架

  4. 产生优越的Python数据解析师

  • 1.1 简介
  • 1.2 实行基本原子操作
  • 1.3 使用Mutex类
  • 1.4 使用SemaphoreSlim类
  • 1.5 使用AutoResetEvent类
  • 1.6 使用ManualResetEventSlim类
  • 1.7 使用CountDownEvent类
  • 1.8 使用Barrier类
  • 1.9 使用ReaderWriterLockSlim类
  • 1.10 使用SpinWait类
  • 参照他事他说加以调查书籍
  • 作者水平有限,倘若不当迎接各位探讨指正!

参照书籍

正文首要参照他事他说加以考察了以下几本书,在那对那一个小编表示由衷的以德报怨您们提供了那样好的资料。

  1. 《CLR via C#》
  2. 《C# in Depth Third Edition》
  3. 《Essential C# 6.0》
  4. 《Multithreading with C# Cookbook Second Edition》
  5. 《C#多线程编制程序实战》

源码下载点击链接 示范源码下载

比如EventHandler,CancelEventHandler,RoutedEventHandler,ContextMenuEventHandler等。

五、分界面效果

5.1、手提式有线电话机端效果

mg4155 23

群内已经有小同伴将文化种类整理好(源码,笔记,PPT,学习摄像),迎接加群免费领到。

1.9 使用ReaderWriterLockSlim类

ReaderWriterLockSlim类重点是一网打尽在好几场景下,读操作多于写操作而采纳一些互斥锁当两个线程同有的时候候做客财富时,独有贰个线程能访谈,引致品质大幅下降。

只要全体线程都愿意以只读的艺术访谈数据,就一贯不须求梗塞它们;倘若二个线程希望改过数据,那么那些线程才供给独自占领访谈,那便是ReaderWriterLockSlim的卓越应用项景。那些类就像是下边那样来决定线程。

  • 三个线程向数据写入是,央浼访谈的任何具有线程都被封堵。
  • 二个线程读取数据时,须要读取的线程允许读取,而哀告写入的线程被封堵。
  • 写入线程甘休后,要么排除二个写入线程的堵截,使写入线程能向数据连接,要么消亡所有读取线程的阻塞,使它们能并发读取多少。假诺线程未有被窒碍,锁就足以进入自由使用的情状,可供下多个读线程或写线程获取。
  • 从数据读取的具有线程截至后,二个写线程被消逝阻塞,使它能向数据写入。倘诺线程没有被打断,锁就足以进去自由使用的景况,可供下叁个读线程或写线程获取。

ReaderWriterLockSlim还协助从读线程晋级为写线程的操作,详情请戳一戳.aspx卡塔尔(英语:State of Qatar)。文本不作介绍。ReaderWriterLock类已经不达时宜,况且存在大多主题材料,未有供给去行使。

亲自过问代码如下所示,创制了3个读线程,2个写线程,读线程和写线程角逐拿到锁。

static void Main(string[] args)
{
    // 创建3个 读线程
    new Thread(() => Read("Reader 1")) { IsBackground = true }.Start();
    new Thread(() => Read("Reader 2")) { IsBackground = true }.Start();
    new Thread(() => Read("Reader 3")) { IsBackground = true }.Start();

    // 创建两个写线程
    new Thread(() => Write("Writer 1")) { IsBackground = true }.Start();
    new Thread(() => Write("Writer 2")) { IsBackground = true }.Start();

    // 使程序运行30S
    Thread.Sleep(TimeSpan.FromSeconds(30));

    Console.ReadLine();
}

static ReaderWriterLockSlim _rw = new ReaderWriterLockSlim();
static Dictionary<int, int> _items = new Dictionary<int, int>();

static void Read(string threadName)
{
    while (true)
    {
        try
        {
            // 获取读锁定
            _rw.EnterReadLock();
            Console.WriteLine($"{threadName} 从字典中读取内容  {DateTime.Now.ToString("mm:ss.ffff")}");
            foreach (var key in _items.Keys)
            {
                Thread.Sleep(TimeSpan.FromSeconds(0.1));
            }
        }
        finally
        {
            // 释放读锁定
            _rw.ExitReadLock();
        }
    }
}

static void Write(string threadName)
{
    while (true)
    {
        try
        {
            int newKey = new Random().Next(250);
            // 尝试进入可升级锁模式状态
            _rw.EnterUpgradeableReadLock();
            if (!_items.ContainsKey(newKey))
            {
                try
                {
                    // 获取写锁定
                    _rw.EnterWriteLock();
                    _items[newKey] = 1;
                    Console.WriteLine($"{threadName} 将新的键 {newKey} 添加进入字典中  {DateTime.Now.ToString("mm:ss.ffff")}");
                }
                finally
                {
                    // 释放写锁定
                    _rw.ExitWriteLock();
                }
            }
            Thread.Sleep(TimeSpan.FromSeconds(0.1));
        }
        finally
        {
            // 减少可升级模式递归计数,并在计数为0时  推出可升级模式
            _rw.ExitUpgradeableReadLock();
        }
    }
}

运作结果如下所示,与预期结果契合。

mg4155 24

1.1 简介

在本章中,重要介绍线程池(ThreadPool)的使用;在C#中它叫System.Threading.ThreadPool,在使用线程池以前率先大家得领会三个标题,那正是干什么要使用线程池。其根本缘由是始建一个线程的代价是高昂的,创造二个线程会损耗过多的系统财富。

那么线程池是怎么样解决那些主题素材的吧?线程池在起来时会自动成立一定量的线程供程序调用,使用时,开辟人士并不直接分配线程,而是将急需做的干活归入线程池工作行列中,由线程池分配已部分线程实行管理,等管理完成后线程不是被销毁,而是双重回回线程池中,那样节约了创办线程的支出。

不过在使用线程池时,须要注意以下几点,那将拾分首要。

  • 线程池不相符管理长日子运作的学业,或许管理须要与其余线程同步的课业。
  • 幸免将线程池中的职业线程分配给I/O首先的天职,这种任务应该运用TPL模型。
  • 如非必需,不要手动设置线程池的最小线程数和最大线程数,CLGL450会自动的举行线程池的恢弘和减弱,手动干预往往让质量更差。

事件是C#中的大器晚成体系型,除了框架为大家定义好的风云外,大家还足以自定义事件,用event关键字来声称。

六、关系表达图

mg4155 25

mg4155 26

mg4155 27

 

无论是线下依然线上,获客和流量都以高转变的前提。

 

以下划重点:

 

微分销系统,让具备参预分享和放大的人都能形成获益者,让新会员、老会员、潜客、消息安全职员成为叁个全部,变异高粘性的闭环

 

声明:文中有个别图片素材来源互连网

 

【开源分享】Wechat营销种类(第三方Wechat平台)github 开源

 

*1 - ***想经过 Python 先导编制程序之旅。

1.3 使用Mutex类

System.Threading.Mutex在概念上和System.Threading.Monitor差相当的少完全一样,可是Mutex手拉手对文本只怕别的跨进度的财富进行拜访,也正是说Mutex是可跨进度的。因为其特点,它的三个用处是限量应用程序无法同时运行四个实例。

Mutex对象协助递归,也正是说同三个线程可再三拿走同叁个锁,那在后面演示代码中可阅览到。由于Mutex的基类System.Theading.WaitHandle实现了IDisposable接口,所以当不必要在动用它时要注意举办能源的刑满释放解除劳教。更加多材质:戳一戳

身体力行代码如下所示,简单的演示了什么样成立单实例的应用程序和Mutex递归获取锁的落到实处。

const string MutexName = "CSharpThreadingCookbook";

static void Main(string[] args)
{
    // 使用using 及时释放资源
    using (var m = new Mutex(false, MutexName))
    {
        if (!m.WaitOne(TimeSpan.FromSeconds(5), false))
        {
            Console.WriteLine("已经有实例正在运行!");
        }
        else
        {

            Console.WriteLine("运行中...");

            // 演示递归获取锁
            Recursion();

            Console.ReadLine();
            m.ReleaseMutex();
        }
    }

    Console.ReadLine();
}

static void Recursion()
{
    using (var m = new Mutex(false, MutexName))
    {
        if (!m.WaitOne(TimeSpan.FromSeconds(2), false))
        {
            // 因为Mutex支持递归获取锁 所以永远不会执行到这里
            Console.WriteLine("递归获取锁失败!");
        }
        else
        {
            Console.WriteLine("递归获取锁成功!");
        }
    }
}

运转结果如下图所示,张开了七个应用程序,因为使用Mutex福寿年高了单实例,所以第2个应用程序无法拿到锁,就能够显得本来就有实例正在运维

mg4155 28

1.6 在线程池中利用等待事件微处理机及超时

本节将介绍怎样在线程池中动用等待职责和哪些进展过期管理,当中注重利用ThreadPool.RegisterWaitForSingleObject()艺术,该措施允许传入三个WaitHandle目标,和急需试行的职分、超时时间等。通过选取那个方式,可做到线程池处境下对过期任务的拍卖。

身体力行代码如下所示,运营了三回使用ThreadPool.RegisterWaitForSingleObject()编辑超时期码的RunOperations()方法,可是所传诵的逾期时间不朝气蓬勃,所以引致二个不容置疑超时和四个不会晚点的结果。

static void Main(string[] args)
{
    // 设置超时时间为 5s WorkerOperation会延时 6s 肯定会超时
    RunOperations(TimeSpan.FromSeconds(5));

    // 设置超时时间为 7s 不会超时
    RunOperations(TimeSpan.FromSeconds(7));
}

static void RunOperations(TimeSpan workerOperationTimeout)
{
    using (var evt = new ManualResetEvent(false))
    using (var cts = new CancellationTokenSource())
    {
        WriteLine("注册超时操作...");
        // 传入同步事件  超时处理函数  和 超时时间
        var worker = ThreadPool.RegisterWaitForSingleObject(evt
            , (state, isTimedOut) => WorkerOperationWait(cts, isTimedOut)
            , null
            , workerOperationTimeout
            , true);

        WriteLine("启动长时间运行操作...");
        ThreadPool.QueueUserWorkItem(_ => WorkerOperation(cts.Token, evt));

        Sleep(workerOperationTimeout.Add(TimeSpan.FromSeconds(2)));

        // 取消注册等待的操作
        worker.Unregister(evt);

        ReadLine();
    }
}

static void WorkerOperation(CancellationToken token, ManualResetEvent evt)
{
    for (int i = 0; i < 6; i++)
    {
        if (token.IsCancellationRequested)
        {
            return;
        }
        Sleep(TimeSpan.FromSeconds(1));
    }
    evt.Set();
}

static void WorkerOperationWait(CancellationTokenSource cts, bool isTimedOut)
{
    if (isTimedOut)
    {
        cts.Cancel();
        WriteLine("工作操作超时并被取消.");
    }
    else
    {
        WriteLine("工作操作成功.");
    }
}

运营结果如下图所示,与预期结果相符。

mg4155 29

代码中,大家运用二种赋值情势,但实际皆感到事件test伊芙nt增添三个委。

                  推广海报

 

mg4155 30

*2 - ***想在数据解析(大数目/金融解析/商业解析/科学解析等)领域前行。

1.5 使用AutoResetEvent类

AutoResetEvent叫自动重新初始化事件,就算名称中有事件大器晚成词,不过重新设置事件和C#中的委托未有任何涉及,这里的事件只是由基本维护的Boolean变量,当事件为false,那么在事变上等候的线程就打断;事件成为true,那么拥塞撤废。

在.Net中有二种此类事件,即AutoResetEvent(自动重置事件)ManualResetEvent(手动重置事件)。那三头均是使用根底格局,它的分化在于当重新设置事件为true时,自行重新载入参数事件它只唤醒叁个堵塞的线程,会活动将事件重置回false,形成任何线程继续窒碍。而手动重新复苏设置事件不会自动重新复苏设置,必需经过代码手动重新载入参数回false

因为以上的缘故,所以在广大稿子和本本中不引入应用AutoResetEvent(自动重置事件),因为它超级轻易在编排生产者线程时产生失误,产生它的迭代次数多余消费者线程。

身体力行代码如下所示,该代码演示了通过AutoResetEvent贯彻几个线程的互相同步。

static void Main(string[] args)
{
    var t = new Thread(() => Process(10));
    t.Start();

    Console.WriteLine("等待另一个线程完成工作!");
    // 等待工作线程通知 主线程阻塞
    _workerEvent.WaitOne();
    Console.WriteLine("第一个操作已经完成!");
    Console.WriteLine("在主线程上执行操作");
    Thread.Sleep(TimeSpan.FromSeconds(5));

    // 发送通知 工作线程继续运行
    _mainEvent.Set();
    Console.WriteLine("现在在第二个线程上运行第二个操作");

    // 等待工作线程通知 主线程阻塞
    _workerEvent.WaitOne();
    Console.WriteLine("第二次操作完成!");

    Console.ReadLine();
}

// 工作线程Event
private static AutoResetEvent _workerEvent = new AutoResetEvent(false);
// 主线程Event
private static AutoResetEvent _mainEvent = new AutoResetEvent(false);

static void Process(int seconds)
{
    Console.WriteLine("开始长时间的工作...");
    Thread.Sleep(TimeSpan.FromSeconds(seconds));
    Console.WriteLine("工作完成!");

    // 发送通知 主线程继续运行
    _workerEvent.Set();
    Console.WriteLine("等待主线程完成其它工作");

    // 等待主线程通知 工作线程阻塞
    _mainEvent.WaitOne();
    Console.WriteLine("启动第二次操作...");
    Thread.Sleep(TimeSpan.FromSeconds(seconds));
    Console.WriteLine("工作完成!");

    // 发送通知 主线程继续运行
    _workerEvent.Set();
}

运行结果如下图所示,与预期结果符合。

mg4155 31


大器晚成,标志提供对事件的响应的不二诀要的嘱托。

                返佣项目清单列表

mg4155 32

mg4155 33 

参照书籍

本文主要仿照效法了以下几本书,在这里对那个笔者表示诚心的感激涕零您们提供了这般好的资料。

  1. 《CLR via C#》
  2. 《C#二十四线程编制程序系列,七年AliPython支出技术员的进级之路。 in Depth Third Edition》
  3. 《Essential C# 6.0》
  4. 《Multithreading with C# Cookbook Second Edition》

源码下载点击链接 躬行实践源码下载

目录

事件和嘱托到底是怎么关联?

                 分销中央

 

mg4155 34

*1 - *** 网址后端技师:使用它单间网址,后台服务比较简单保险。如:Gmail、Youtube、果壳网、豆瓣。

1.1 简介

本章介绍在C#中落到实处线程同步的三种方法。因为四个线程同时访谈分享数据时,恐怕会导致分享数据的毁坏,进而造成与预期的结果不符合。为了消弭那么些标题,所以须求用到线程同步,也被俗称为“加锁”。但是加锁相对不对进步质量,最多也正是不增不减,要贯彻品质不增不减还得靠高水平的同步源语(Synchronization Primitive卡塔尔(قطر‎。可是因为不错永久比速度更主要,所以线程同步在好几场景下是必得的。

线程同步有二种源语(Primitive卡塔尔架构:客商形式(user - mode卡塔尔(英语:State of Qatar)功底情势(kernel - mode卡塔尔(قطر‎,当财富可用时间短的场合下,顾客方式要优于根本格局,但是假若长日子无法获得能源,可能说长日子处于“自旋”,那么内核情势是绝对来讲好的筛选。

可是大家希望保有客商格局和水源格局的亮点,大家把它称作混合布局(hybrid construct卡塔尔(قطر‎,它有着了三种形式的帮助和益处。

在C#中有种种线程同步的体制,经常可以遵从以下顺序实行选用。

  1. 若是代码能经过优化能够不开展合营,那么就绝不做生龙活虎道。
  2. 使用原子性的Interlocked方法。
  3. 使用lock/Monitor类。
  4. 利用异步锁,如SemaphoreSlim.WaitAsync()
  5. 运用其他加锁机制,如ReaderWriterLockSlim、Mutex、Semaphore等。
  6. 假使系统提供了*Slim本子的异步对象,那么请选取它,因为*Slim本子全是混合锁,在进入底工形式前贯彻了某种格局的自旋。

在同步中,必要求小心制止死锁的发生,死锁的发生必得知足以下4个主导准绳,所以只需求破坏率性三个规范化,就可制止发生死锁。

  1. 排他或互斥(Mutual exclusion卡塔尔(英语:State of Qatar):一个线程(ThreadA卡塔尔国独自据有三个财富,未有此外线程(ThreadB卡塔尔国能得到相符的财富。
  2. 攻陷并等候(Hold and wait卡塔尔(قطر‎:互斥的贰个线程(ThreadA卡塔尔央求获取另二个线程(ThreadB卡塔尔国据有的财富.
  3. 不足超过(No preemption卡塔尔(قطر‎:贰个线程(ThreadA卡塔尔(英语:State of Qatar)据有财富不能够被挟持拿走(只好等待ThreadA主动释放它的能源卡塔尔。
  4. mg4155,循环等待条件(Circular wait condition卡塔尔(قطر‎:多个或五个线程构成三个周而复始等待链,它们锁定七个或八个黄金年代律的财富,每种线程都在等待链中的下五个线程据有的能源。

EventHandler:

                        发表路子召集令

mg4155 35

                        mg4155 36

mg4155 37 

1.4 使用SemaphoreSlim类

SemaphoreSlim类与事情发生在此之前提到的协作类有锁差异,以前涉嫌的同步类都以排挤的,也等于说只同意二个线程实行拜望能源,而SemaphoreSlim是能够允许八个访谈。

在事情发生以前的风姿洒脱部分有关联,以*Slim最终的线程同步类,都是做事在混合方式下的,也等于说开首它们都以在客户方式下"自旋",等发生第一回竞争时,才切换来根底方式。但是SemaphoreSlim不同于Semaphore类,它不协理系统实信号量,所以它无法用于进程之间的同步

该类应用比较简单,演示代码演示了6个线程竞争访谈只允许4个线程同期做客的数据库,如下所示。

static void Main(string[] args)
{
    // 创建6个线程 竞争访问AccessDatabase
    for (int i = 1; i <= 6; i++)
    {
        string threadName = "线程 " + i;
        // 越后面的线程,访问时间越久 方便查看效果
        int secondsToWait = 2 + 2 * i;
        var t = new Thread(() => AccessDatabase(threadName, secondsToWait));
        t.Start();
    }

    Console.ReadLine();
}

// 同时允许4个线程访问
static SemaphoreSlim _semaphore = new SemaphoreSlim(4);

static void AccessDatabase(string name, int seconds)
{
    Console.WriteLine($"{name} 等待访问数据库.... {DateTime.Now.ToString("HH:mm:ss.ffff")}");

    // 等待获取锁 进入临界区
    _semaphore.Wait();

    Console.WriteLine($"{name} 已获取对数据库的访问权限 {DateTime.Now.ToString("HH:mm:ss.ffff")}");
    // Do something
    Thread.Sleep(TimeSpan.FromSeconds(seconds));

    Console.WriteLine($"{name} 访问完成... {DateTime.Now.ToString("HH:mm:ss.ffff")}");
    // 释放锁
    _semaphore.Release();
}

运作结果如下所示,可见前4个线程登时就拿到到了锁,走入了临界区,而除此以外四个线程在等候;等有锁被保释时,才具跻身临界区。mg4155 38

故此,事件在现在的编制程序中,很恐怕将不在有那么首要的地位了。但学好事件,对于大家清楚微软框架,依旧有十分的大扶持的。

3.为办事实战打下功底

注:此作品为原创,应接转发,请在随笔页面显著地方给出此文链接!
若你以为那篇小说能够选拔,请点击下右下角的【推荐】,非常感激!
例如您感到那篇小说对你抱有利于,那就不妨支付宝小小打赏一下吗。 

本文由mg4155com发布于mg4155线路检测手机版,转载请注明出处:二十四线程编制程序系列,七年AliPython支出技术

关键词:

上一篇:机动达成高品质MVC,List集结去重使用lambda表达式

下一篇:没有了