我有一个包含 7 列和 10 行的数据库表。每行都为 Web API 调用提供一个输入参数,并将 API 返回的响应插入到表中。我的问题是,Parallel.Foreach
没有产生与常规ForEach相同的结果。
具体来说,如果第一行的地址是"123 Jump Street Arizona Us",我从 web api 收到一个响应,标准化地址为"123 Jump Street Arizona USA",就像我有 10 个不同的行,有 10 个不同的输入地址。 但是,我从Parallel.Foreach
得到的输出响应是针对重复 5 次的同一地址。下次我运行它时,结果完全不同
有人可以指出为什么会发生这种情况以及潜在的解决方案吗?
这是我的代码:
public void Main()
{
// TODO: Add your code here
string query = "SELECT ADDR_LINE_ONE,ADDR_LINE_TWO,ADDR_LINE_THREE,COUNTRY,PROVINCE,CITY_NAME,POSTAL_CODE FROM Addresstestpoc";
try
{
using (OleDbConnection connection = new OleDbConnection(conn))
{
OleDbCommand command = new OleDbCommand(query, connection);
connection.Open();
OleDbDataReader reader = command.ExecuteReader();
int i = reader.FieldCount;
bool b = reader.HasRows;
Parallel.ForEach(GetFromReader(reader), record =>
{
//AddrOne = record[0].ToString();
string AddrOne = record.GetString(0);
string AddrTwo = record.GetString(1);
string AddrThree = record.GetString(2);
string Country = record.GetString(3);
string Province = record.GetString(4);
string City = record.GetString(5);
string PostalCode = record.GetString(6);
string Sender = "G";
//sqlk = (string)Dts.Variables["User::sqlconn"].Value;
standardizeAddressReturn result;
string data = string.Empty;
string queri;
MDMStandardizeAddressService web = new MDMStandardizeAddressService();
try
{
result = web.standardizeAddress(AddrOne, AddrTwo, AddrThree, City, Province, PostalCode, Country, Sender);
data = SerializeToXml(result);
queri = "insert into [CPM].[dbo].[AddressResponsetest_new] values ('" + data + "')";
//MessageBox.Show(data);
insertintosql(queri);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
});
}
}
catch (Exception ex)
{
string msg = ex.Message;
}
}
IEnumerable<IDataRecord> GetFromReader(IDataReader reader)
{
while (reader.Read()) yield return reader;
}
我认为你需要另一种方法。 命令和数据读取器不是线程安全的。 即使 DataReader 是线程安全的,它也是一个仅向前的游标,因此它不会更快。
我推荐生产者消费者模式(.e.g BlockingCollection(。在消费者中,您可以并行处理
MDMStandardizeAddressService web = new MDMStandardizeAddressService();
try
{
您可能可以使用任务,等待,异步生产者消费者。
一种更简单的方法可能是为属性创建一个类并将其放在列表中,然后只读取该列表。 这将发生在几分之一秒内。
然后,您可以并行处理列表。
存根代码:
public class WebMailer
{
public void process()
{
List<Addr> Addrs = new List<Addr>();
SqlCommand command = new SqlCommand();
using (var reader = command.ExecuteReader())
{
using (SqlDataReader r = command.ExecuteReader())
{
Addrs.Add(new Addr(r.GetString(0), r.GetString(1)));
}
}
foreach(Addr addr in Addrs) // can use parallel here
{ }
}
}
s