我在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;
}
}
}
答案 0 :(得分:2)
您的第一个问题是您要从多个线程修改DataTable
。 documentation说:
此类型对于多线程读取操作是安全的。您必须同步任何写操作。
所以你有多个线程都盲目地更新表。如果其中两个或多个尝试同时进行更新,则结果无法预测。他们可能不你想要的东西。
如果你继续进行同步,我会非常惊讶地发现多线程版本比单线程版本运行得更快。如果您的所有线程都在向表中添加内容,那么他们将花费大部分时间等待锁定。您使用多个线程没有任何好处,因为线程并没有做多少并行。
简而言之,在这种情况下使用多线程并不是一场胜利。省去麻烦,用一个线程来完成。
答案 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
,参考: