在 C# 线程中循环

looping in c# threading

我正在用 C# 开发 Web 应用程序。此应用程序使用来自其他应用程序的 API,其中 returns 我想转换为数据表的对象数组。我的应用程序的第一个版本使用 for 循环将数组中的所有对象一个一个地添加到数据表中。这个版本正确地完成了工作,但需要一些时间来处理。

所以我决定继续使用多线程并减少处理时间,因为我要部署我的应用程序的服务器有多个内核。但是我想动态地创建线程以在未来的项目中实现代码的可扩展性和可重用性。

当我执行该应用程序时,第一次它运行得非常好,第二次它就循环了。我遇到的错误似乎是线程内的无限循环,但不知道它在哪里。

请大家帮忙。下面是我的代码:

Hilos2.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Hilos2.aspx.cs" Inherits="Hilos2" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <asp:GridView id="gvrandom" runat="server" AutoGenerateColumns="true">        </asp:GridView>
    </div>
</form>
</body>
</html>

Hilos2.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Threading;
using System.Data;

public partial class Hilos2 : System.Web.UI.Page
{
    clsValues[] vals = new clsValues[1038];

    DataSet ds = new DataSet();

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            ds.Tables.Add("Out");

            ds.Tables["Out"].Columns.AddRange(new[] { new     DataColumn("Value1", typeof(string)), new DataColumn("Value2", typeof(string)) });

            /*this section is just to represent the array i get from the api
            the size of the array are similar*/
            Random rand = new Random();
            for (int i = 0; i < 1038; i++)
            {
                vals[i] = new clsValues();
                vals[i].Value1 = Convert.ToChar(rand.Next(1, 256)).ToString() + Convert.ToChar(rand.Next(1, 256)).ToString() + Convert.ToChar(rand.Next(1, 256)).ToString() +
                    Convert.ToChar(rand.Next(1, 256)).ToString() + Convert.ToChar(rand.Next(1, 256)).ToString();
                vals[i].Value2 = Convert.ToChar(rand.Next(1, 256)).ToString() + Convert.ToChar(rand.Next(1, 256)).ToString() + Convert.ToChar(rand.Next(1, 256)).ToString() +
                    Convert.ToChar(rand.Next(1, 256)).ToString() + Convert.ToChar(rand.Next(1, 256)).ToString();
            }

            int elementsXthread = (int)Math.Truncate((double)(vals.Length / Environment.ProcessorCount));
            int elementsLastThread;
            int elementsToProcess;
            int posStartProcess = 0;
            List<Thread> thr = new List<Thread>();

            if (elementsXthread * Environment.ProcessorCount != vals.Length)
            {
                elementsLastThread = elementsXthread + vals.Length - (elementsXthread * Environment.ProcessorCount);
            }
            else
            {
                elementsLastThread = elementsXthread;
            }

            elementsToProcess = elementsXthread;

            for (int i = 1; i < Environment.ProcessorCount + 1; i++)
            {
                if (i == Environment.ProcessorCount)
                {
                    elementsToProcess = elementsLastThread;
                }
                if (elementsToProcess + posStartProcess <= vals.Length)
                {
                    int param1, param2;
                    param1 = elementsToProcess;
                    param2 = posStartProcess;
                    Thread tdr = new Thread(() => rnd(param1, param2));
                    tdr.Start();
                    thr.Add(tdr);
                    posStartProcess += elementsToProcess;
                }
            }
            foreach (Thread tdr in thr)
            {
                tdr.Join();
            }

            gvrandom.DataSource = ds.Tables["Out"];
            gvrandom.DataBind();
        }
    }

    private void rnd(int iter, int posinicio)
    {

        for (int iterador = 0; iterador < iter; iterador++)
        {
            System.Data.DataRow dr = ds.Tables["Out"].NewRow();
            dr["Value1"] = vals[iterador + posinicio].Value1;
            dr["Value2"] = vals[iterador + posinicio].Value2;
            ds.Tables["Out"].Rows.Add(dr);
        }
    }
}
public class clsValues
{
    string value1, value2;

    public string Value1
    {
        get
        {
            return value1;
        }
        set
        {
            value1 = value;
        }
    }

    public string Value2
    {
        get
        {
            return value2;
        }
        set
        {
            value2 = value;
        }
    }
}

您没有阻止线程争用。线程在与 ds 交互时都在发生冲突。

一个。声明一个锁。

private object myLock = new object();

乙。在 rand 方法中使用锁:

 private void rnd(int iter, int posinicio)
 {

    for (int iterador = 0; iterador < iter; iterador++)
    {
        System.Data.DataRow dr = ds.Tables["Out"].NewRow();
        dr["Value1"] = vals[iterador + posinicio].Value1;
        dr["Value2"] = vals[iterador + posinicio].Value2;
        lock (myLock)
        {
            ds.Tables["Out"].Rows.Add(dr);
        }
    }
}

您的第一个问题是您正在从多个线程修改 DataTabledocumentation 表示:

This type is safe for multithreaded read operations. You must synchronize any write operations.

所以你有多个线程都在盲目地更新 table。如果他们中的两个或更多人同时尝试进行更新,则结果是不可预测的table。他们可能不是你想要的。

如果您继续进行同步,我会非常惊讶地发现多线程版本比单线程版本运行得更快。如果您的线程所做的只是向 table 添加内容,那么它们将花费大部分时间等待锁。使用多个线程不会给您带来任何好处,因为线程并行执行的工作不多。

简而言之,在这种情况下使用多线程并不成功。为自己省去麻烦,使用单线程完成此操作。

这是实现多线程的糟糕方法,尤其是在 ASP.NET 应用程序中,并且根本没有线程安全性。

但是更好的方法是使用专门针对这种情况设计和创建的PageAsyncTask,参考:

MSDN PageAsyncTask