循环使用c#线程

时间:2015-04-07 15:48:06

标签: c# multithreading infinite-loop

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

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

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

暂停任何人。以下是我的代码:

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;
        }
    }
}

3 个答案:

答案 0 :(得分:2)

您的第一个问题是您要从多个线程修改DataTabledocumentation说:

  

此类型对于多线程读取操作是安全的。您必须同步任何写操作。

所以你有多个线程都盲目地更新表。如果其中两个或多个尝试同时进行更新,则结果无法预测。他们可能你想要的东西。

如果你继续进行同步,我会非常惊讶地发现多线程版本比单线程版本运行得更快。如果您的所有线程都在向表中添加内容,那么他​​们将花费大部分时间等待锁定。您使用多个线程没有任何好处,因为线程并没有做多少并行。

简而言之,在这种情况下使用多线程并不是一场胜利。省去麻烦,用一个线程来完成。

答案 1 :(得分:1)

您不能阻止线程争用。线程在与ds交互时都会发生冲突。

一个。宣布锁定。

private object myLock = new object();

B中。在rand方法中使用lock:

 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);
        }
    }
}

答案 2 :(得分:0)

这是实现多线程的一种不好的方法,尤其是在ASP.NET应用程序中,根本没有线程安全。

然而,更好的方法是使用专为此类案例设计和创建的PageAsyncTask,参考:

MSDN PageAsyncTask