如何确保线程安全的ASP.net页面访问静态对象列表

发布于 2024-12-17 14:46:42 字数 3233 浏览 0 评论 0原文

在我的网络应用程序中,我为所有在线用户提供了以下通用对象列表。

public static List<MyClass> myObjectList = new List<MyClass>();

因此,当多个在线用户尝试从该对象myObjectList读取数据时,是否有可能出现线程同步问题

在另一种情况下,多个用户正在从 myObjectList 读取数据,其中很少有人也在写入,但每个用户都在 List 的不同 索引 上写入。每个用户都可以向该列表添加新项目。所以现在我认为有可能存在同步问题

如何编写线程安全实用程序类,可以以更安全的方式从此对象读取和写入数据。

非常欢迎提出建议

Angelo 建议的代码看起来像这样,

using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;


namespace ObjectPoolExample
{
    public class ObjectPool<T>
    {
        private ConcurrentBag<T> _objects;
        private Func<T> _objectGenerator;

        public ObjectPool(Func<T> objectGenerator)
        {
            if (objectGenerator == null) throw new ArgumentNullException("objectGenerator");
            _objects = new ConcurrentBag<T>();
            _objectGenerator = objectGenerator;
        }

        public T GetObject()
        {
            T item;
            if (_objects.TryTake(out item)) return item;
            return _objectGenerator();
        }

        public void PutObject(T item)
        {
            _objects.Add(item);
        }
    }

    class Program
    {
       static void Main(string[] args)
        {
            CancellationTokenSource cts = new CancellationTokenSource();

            // Create an opportunity for the user to cancel.
            Task.Factory.StartNew(() =>
                {
                    if (Console.ReadKey().KeyChar == 'c' || Console.ReadKey().KeyChar == 'C')
                        cts.Cancel();
                });

            ObjectPool<MyClass> pool = new ObjectPool<MyClass> (() => new MyClass());            

            // Create a high demand for MyClass objects.
            Parallel.For(0, 1000000, (i, loopState) =>
                {
                    MyClass mc = pool.GetObject();
                    Console.CursorLeft = 0;
                    // This is the bottleneck in our application. All threads in this loop
                    // must serialize their access to the static Console class.
                    Console.WriteLine("{0:####.####}", mc.GetValue(i));                 

                    pool.PutObject(mc);
                    if (cts.Token.IsCancellationRequested)
                        loopState.Stop();                 

                });
            Console.WriteLine("Press the Enter key to exit.");
            Console.ReadLine();
        }

    }

    // A toy class that requires some resources to create.
    // You can experiment here to measure the performance of the
    // object pool vs. ordinary instantiation.
    class MyClass
    {
        public int[] Nums {get; set;}
        public double GetValue(long i)
        {
            return Math.Sqrt(Nums[i]);
        }
        public MyClass()
        {
            Nums = new int[1000000];
            Random rand = new Random();
            for (int i = 0; i < Nums.Length; i++)
                Nums[i] = rand.Next();
        }
    }   
}

我想我可以采用这种方法。

In my web application i am having following common objectList for all online users.

public static List<MyClass> myObjectList = new List<MyClass>();

so when multiple online users try to read data from this object myObjectList then are there any chances of thread synchronization issue.

In another scenario multiple users are reading from myObjectList and few of them are writing also but every user is writing on a different index of List . Every user may add a new item to this list . So now I think there are chances of synchronization issue.

How to write thread safe utility class that can read and write data from this object in safer way.

Suggestions are highly welcome

Code suggested by Angelo looks like this

using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;


namespace ObjectPoolExample
{
    public class ObjectPool<T>
    {
        private ConcurrentBag<T> _objects;
        private Func<T> _objectGenerator;

        public ObjectPool(Func<T> objectGenerator)
        {
            if (objectGenerator == null) throw new ArgumentNullException("objectGenerator");
            _objects = new ConcurrentBag<T>();
            _objectGenerator = objectGenerator;
        }

        public T GetObject()
        {
            T item;
            if (_objects.TryTake(out item)) return item;
            return _objectGenerator();
        }

        public void PutObject(T item)
        {
            _objects.Add(item);
        }
    }

    class Program
    {
       static void Main(string[] args)
        {
            CancellationTokenSource cts = new CancellationTokenSource();

            // Create an opportunity for the user to cancel.
            Task.Factory.StartNew(() =>
                {
                    if (Console.ReadKey().KeyChar == 'c' || Console.ReadKey().KeyChar == 'C')
                        cts.Cancel();
                });

            ObjectPool<MyClass> pool = new ObjectPool<MyClass> (() => new MyClass());            

            // Create a high demand for MyClass objects.
            Parallel.For(0, 1000000, (i, loopState) =>
                {
                    MyClass mc = pool.GetObject();
                    Console.CursorLeft = 0;
                    // This is the bottleneck in our application. All threads in this loop
                    // must serialize their access to the static Console class.
                    Console.WriteLine("{0:####.####}", mc.GetValue(i));                 

                    pool.PutObject(mc);
                    if (cts.Token.IsCancellationRequested)
                        loopState.Stop();                 

                });
            Console.WriteLine("Press the Enter key to exit.");
            Console.ReadLine();
        }

    }

    // A toy class that requires some resources to create.
    // You can experiment here to measure the performance of the
    // object pool vs. ordinary instantiation.
    class MyClass
    {
        public int[] Nums {get; set;}
        public double GetValue(long i)
        {
            return Math.Sqrt(Nums[i]);
        }
        public MyClass()
        {
            Nums = new int[1000000];
            Random rand = new Random();
            for (int i = 0; i < Nums.Length; i++)
                Nums[i] = rand.Next();
        }
    }   
}

I think i can go with this approach.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

爱*していゐ 2024-12-24 14:46:42

如果您使用 .NET 4.0,最好更改为 线程安全之一运行时已支持的集合,例如 ConcurrentBag

但是,如果我没记错的话,并发包不支持按索引访问,因此您可能需要求助于 ConcurrentDictionary 如果您需要通过给定键访问对象。

如果 .NET 4.0 不是一个选项,您应该阅读以下博客文章:

为什么线程安全集合如此困难?

If you are using .NET 4.0 you are better off changing to one of the thread-safe collections already supported by the runtime, like for example a ConcurrentBag.

The concurrent bag however does not support access by index if I recall correctly so you may need to resort to a ConcurrentDictionary if you need access to an object by a given key.

If .NET 4.0 is not an option you should read the following blog post:

Why are thread safe collections so hard?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文