ASP.NET多线程的使用

2022-11-29 15:26:22 浏览数 (1)

多线程概述:

        线程,是操作系统中的术语,是操作系统进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。一个进程可以有很多线程,每条线程并行执行不同的任务。同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。我们把用来执行用户任务的线程称为工作线程。而线程池,是一种成熟的线程使用模式。

为什么要创建线程池?

  线程池属于对象池.所有对象池都具有一个非常重要的共性,就是为了最大程度复用对象.那么,线程池的最重要的特征也就是最大程度利用线程。所以线程池的目的就是为了减少创建和切换线程的额外开销,利用已经的线程多次循环执行多个任务从而提高系统的处理能力。

  在ASP.NET工作进程中有两种线程池,Worker线程池处理所有传入的请求, I / O线程池处理的I / O(访问文件系统,Web服务和数据库等)。每个应用程序域都有其自己的线程池,可以排队到线程池的操作的数量只受可用内存的限制,然而,对线程池中的线程数的限制在这个过程中可以同时被激活。 

        当我们发出一个(异步)页面请求。一个Worker线程就会被从Worker线程池中取出, 这个Worker线程会触发I/O操作。当I/O操作开始时,另一个线程将会被从I/O线程池中取出,在收到I/O线程的返回值之前,Worker线程会一直处于闲置状态。所以,如果你的页面加载事件触发了多个I/O操作,那么,Worker线程就很可能会被闲置很长时间。而线程池能够把正处于闲置状态的Worker线程回收,使他能够为其他的页面请求提供服务。从而,降低系统开销。

演示demo(创建控制台项目):

测试编码:

代码语言:javascript复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace duo_0926
{
    class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(() => {
                Console.WriteLine("启动吃药的监听:输入1代表吃药");
                Ation1();
            });
            t1.Start();
            Thread t2 = new Thread(() => {
                Console.WriteLine("启动攻击的监听:输入2代表攻击");
                Ation2();
            });
            t2.Start();
            
        }
        /// <summary>
        /// 吃药的监听
        /// </summary>
        public static void Ation1() {
            while (true)
            {
                string ctrl = Console.ReadLine();
                if (ctrl.Equals("1")) {
                    Console.WriteLine("吃药,血量增加200点。");
                }
            }
        }

        /// <summary>
        /// 攻击的监听
        /// </summary>
        public static void Ation2()
        {
            while (true)
            {
                string ctrl = Console.ReadLine();
                if (ctrl.Equals("2"))
                {
                    Console.WriteLine("攻击,对敌方造成200点伤害。");
                }
            }
        }
    }
}

当输入过快的时候无法被循环监听到:

一同运行,相当于两个线程会交替的进行执行。故而会出现如上现象。所以咱们开启线程的时候尽量进行同样的功能处理同样的事情。

演示代码:

代码语言:javascript复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace duo_0926
{
    class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(() => {
                Ation1();
            });
            t1.Start();
            Thread t2 = new Thread(() => {
                Ation2();
            });
            t2.Start();
            
        }
        /// <summary>
        /// 线程1
        /// </summary>
        public static void Ation1() {
            for (int i = 0; i < 100; i  )
            {
                Console.WriteLine("线程1:" i);
            }
        }

        /// <summary>
        /// 线程2
        /// </summary>
        public static void Ation2()
        {
            for (int i = 0; i < 100; i  )
            {
                Console.WriteLine("线程2:"   i);
            }
        }
    }
}

执行效果:

 以上效果可以说明,两个线程是相互交替执行,并非共同执行。

所以说,如果进行同时监听,无法正确进行线程操作。

通过如下方法即可进行线程交互:

Thread.Sleep(1);//休息1毫秒,不争抢线程

代码语言:javascript复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace duo_0926
{
    class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(() => {
                Ation1();
            });
            t1.Start();
            Thread t2 = new Thread(() => {
                Ation2();
            });
            t2.Start();
            
        }
        /// <summary>
        /// 线程1
        /// </summary>
        public static void Ation1() {
            for (int i = 0; i < 100; i  )
            {
                Thread.Sleep(1);
                Console.WriteLine("线程1:" i);
            }
        }

        /// <summary>
        /// 线程2
        /// </summary>
        public static void Ation2()
        {
            for (int i = 0; i < 100; i  )
            {
                Thread.Sleep(1);
                Console.WriteLine("线程2:"   i);
            }
        }
    }
}

可以看到,两个线程基本上都是在交互执行: 

 多次执行总会找到无法交互的地方。

 说明线程休息的时间简短,线程1并没有争抢线程成功。可以加大线程休息时间。

Thread.Sleep(5);//每次线程休息5毫秒

重新测试,多次执行,出现争抢失败的情况就很少了:

重新测试监听: 

代码语言:javascript复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace duo_0926
{
    class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(() => {
                Console.WriteLine("启动吃药的监听:输入1代表吃药");
                Ation1();
            });
            t1.Start();
            Thread t2 = new Thread(() => {
                Console.WriteLine("启动攻击的监听:输入2代表攻击");
                Ation2();
            });
            t2.Start();

        }
        /// <summary>
        /// 吃药的监听
        /// </summary>
        public static void Ation1()
        {
            while (true)
            {
                Thread.Sleep(1);
                string ctrl = Console.ReadLine();
                if (ctrl.Equals("1"))
                {
                    Console.WriteLine("吃药,血量增加200点。");
                }
            }
        }

        /// <summary>
        /// 攻击的监听
        /// </summary>
        public static void Ation2()
        {
            while (true)
            {
                Thread.Sleep(1);
                string ctrl = Console.ReadLine();
                if (ctrl.Equals("2"))
                {
                    Console.WriteLine("攻击,对敌方造成200点伤害。");
                }
            }
        }
    }
}

创建web api项目进行接口测试

创建WebAPI项目,方便测试

修改【App_Start/WebApiConfig.cs】配置文件

添加取消XML返回配置

代码语言:javascript复制
//取消XML返回
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();

添加{action}访问路径设置

代码语言:javascript复制
routeTemplate: "api/{controller}/{action}/{id}",

添加【API】接口:

依次选择【Web API】->【Web API 2 控制器 - 空】->【添加】:

输入文件名【Test】,点击【添加】

【TestController.cs】编码:

代码语言:javascript复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Web.Http;

namespace webApi.Controllers
{
    public class TestController : ApiController
    {
        /// <summary>
        /// 计时器
        /// </summary>
        public static int times = 0;
        /// <summary>
        /// 计时器开关
        /// </summary>
        public static bool ctrl = false;
        /// <summary>
        /// 开启计时器线程
        /// </summary>
        /// <param name="type">0、关闭<br/>1、开启</param>
        /// <returns></returns>
        [HttpGet]
        public object StartTime(string type)
        {
            ctrl = type.Equals("0") ? false : Times();
            return ctrl ? "启动成功" : "关闭成功";
        }
        /// <summary>
        /// 获取计时的时间
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public object GetTime() {
            return times;
        }
        /// <summary>
        /// 开启计时
        /// </summary>
        /// <returns></returns>
        private bool Times() {
            Thread t = new Thread(()=>{
                while (ctrl) {
                    Thread.Sleep(1000);//休息1秒
                    times  = 1;
                }
            });
            //启动
            t.Start();
            return true;
        }
    }
}

代码功能测试:

设为启动项:

启动项目:

选择【API】

两个接口都可以看到:

 访问方式:

【http://localhost:2298/api/Test/StartTime?type=0】开启或关闭

 【http://localhost:2298/api/Test/GetTime】获取时间

开启测试:

http://localhost:2298/api/Test/StartTime?type=1

 稍等一会测试时间:【http://localhost:2298/api/Test/GetTime】

关闭测试:

可以看到试用多线程可以当然控制时间,控制开关操作,那么这类操作基本上都会在各种活动中用到,我之前的老总就喜欢各种各样的活动,每次我都会做类似的开关。当然,这个东西不仅仅用在这个地方,还有很多的环境都会用到,咱们要做到具体问题具体分析,可以在编码过程中为大家解决很多问题

0 人点赞