Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / ASP.NET [игнор отключен] [закрыт для гостей] / потоки с#, ошибка / 12 сообщений из 12, страница 1 из 1
21.08.2012, 22:36
    #37925354
GeneralMotors
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
потоки с#, ошибка
здравствуйте!
возникла необходимость некое работающее приложение сделать многопоточным в связи с большими временными затратами,первый раз работаю с потоками.
переделывая , наткнулся на след-ю ошибку, может подскажете в чем может быть дело.
есть поток:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
Thread threadFirst3 = new Thread(delegate() {CreateRepLoadData(_begNum2, _endNum2, 3); });
...
 public void CreateRepLoadData(int _begNum, int _endNum, int _numThread)
 {
           ....
            int cntReport=0;
     
            cntReport = GetCntReport(_begNum, _endNum)
  }
  public int GetCntReport(int _begNum, int _endNum)
  {
            int cnt = 0;
  

                String strCom = " select count(*) as F1 from ( select rownum, PK  from  (  select row_number() over (order by PK ) as rownum,  PK ";
                strCom += " from table1 where Id=" + ID + " and PK_Id=4900  ) a  where a.rownum between " + _begNum + " and " + _endNum + ") b ";

                SqlCommand _com = new SqlCommand(strCom, SQLCon);

                if (SQLCon.State != ConnectionState.Open)
                {
                    SQLCon.Open();
                }
                lock (_com)
                {
                    cnt = Convert.ToInt32(_com.ExecuteScalar());
                    _com.Dispose();
                    return cnt;
                }
           
   }


на ф-ии GetCntReport получаю run-time error {"Существует назначенный этой команде открытый DataReader, который требуется предварительно закрыть."}
что не так, не пойму
заранее спасибо всем ответившим!
...
Рейтинг: 0 / 0
21.08.2012, 23:43
    #37925392
bazile
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
потоки с#, ошибка
GeneralMotors, ошибка говорит сама за себя - SqlConnection может выполнять по одной команде за раз. Т.к. переменная SQLCon у тебя не локальная, то она используется где-то еще. Скорее всего в этой же функции т.к. ты видимо создаешь несколько потоков для нее. Решение - открывать и закрывать соединение внутри функции GetCntReport или использовать открывать соединение с параметром MultipleActiveResultSets=true (это называется MARS).

Кроме того в коде есть и другие проблемы:
1) ASP.NET не будет ждать завершения твоих потоков, тебе нужно вручную убеждаться что код в потоках завершился. Лучшим выбором будет ThreadPool.QueueUserWorkItem(). Но тут начинается другая проблема - ты будешь "отбирать" потоки у ASP.NET так что есть смысд увеличить максимальное кол-во рабочих потоков доступных для ASP.NET - см. справку по <processModel> .
2) lock на локальной переменной не нужен
3) вместо явного вызова Dispose() следует использовать using() { ... }
4) Пользуйся запросами с параметрами. При их использовании SQL Server сможет закешировать план исполнения, а не будет строит его заново каждый раз. Кроме того параметры защитят твое приложение от SQL Injection атак. В данном случае это не важно т.к. у тебя параметры типа int, но тем не менее.
5) С чего ты решил что многопоточность ускорит твое приложение? Где именно узкое место? Если БД, то следует начать с уменьшения кол-ва запросов, их оптимизации, попробовать кеширование результатов.

Многопоточность _может_ ускорить приложение. При одном условии - грамотное применение. Раз у тебя нет опыта работы с ними, то велика вероятность наломать дров. Попробуй сначала оптимизации без использования многопоточности.
...
Рейтинг: 0 / 0
22.08.2012, 09:57
    #37925663
GeneralMotors
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
потоки с#, ошибка
bazile,
спасибо за советы!

функциональность приложениея состоит в том что на основе некоего списка ID шников формируются кристаловские отчеты, сохраняющиеся потом в формате pdf и записывает эти пдф-ники в базу. Отчеты формируются в цикле поштучно. Минимум какого удалось добиться 1.2сек на один отчет - это много, потому как допустим список из 700000-8000000 шт . Запросов к БД мало, они пустяковые и выполняются за доли секунд.
приведу кусок кода формирущего непосредственно отчеты, мож подскажете где можно сократить.
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
      public void CreateRepLoadData(int _begNum, int _endNum, int _numThread)
        {
            FileInfo f;
            int curNumRep = 1;
            int cntPD = 0; // кол-во ПД в отчете , 2 ПД = одна страница
            int cntPDPage = 0; // кол-во страниц с ПД на экране
            int cntSheet = 0; //кол-во листов
            int cntPageBeg = 0; // кол-во страниц пдф файла
            int D270Cur = 0; // FN1534.D270 текущего уведомления 
            ArrayList D270 = new ArrayList();//массив D270 для пачки уведомлений, получаем из тбл списка для ТП
            int cntReport=0;
            //создаем отчет
            
            cntReport = GetCntReport(_begNum, _endNum);
           
            GetArrayD270(_begNum, _endNum,D270);

            ReportDocument rd = new ReportDocument();
            //   загружаем  rpt-шник
            GetTemplateReport();
            String Path = MainPath + @"\tmplReport.rpt";
            rd.Load(Path);
            logEvent.AppendText("загрузка отчета из файла произведена успешно");
            try 
            {

              logEvent.AppendText("кол-во уведомлений =" + cntReport);
                for (int i = 1; i <= _endNum - _begNum + 1; i++)
                {
                    D270Cur = (int)D270[i - 1];
                    exProc2(Convert.ToInt32(D270[i - 1]));
                    curNumRep = i;
                    logEvent.AppendText("начато формирование отчета с номером " + i);
                    rd.Load(Path);

                    ///////////set printers options ////////////////////
                    rd.PrintOptions.ApplyPageMargins(new PageMargins(1, 1, 1, 1));
                    //////////////////////////////////////////////////
                    // устанавливаем датасет
                    try //
                    {
                        rd.Database.Tables[0].SetDataSource(DS.Tables[0]);
                        logEvent.AppendText("установка датасета для основного отчета");

                        cntPD = (int)DS.Tables[0].Rows[i - 1][44];
                        D270Cur =(int)D270[i - 1];

                        rd.Subreports["UvedFL_CalcL_Trp.rpt"].Database.Tables[0].SetDataSource(DS.Tables[2]);
                        rd.Subreports["UvedFL_CalcL_Lnd.rpt"].Database.Tables[0].SetDataSource(DS.Tables[2]);
                        rd.Subreports["UvedFL_CalcL_Real.rpt"].Database.Tables[0].SetDataSource(DS.Tables[2]);
                        logEvent.AppendText("установка датасета для подотчета UvedFL_CalcL_Trp.rpt");

                        rd.Subreports["UvedFL_GNI.rpt"].Database.Tables[0].SetDataSource(DS.Tables[1]);

                        logEvent.AppendText("установка датасета для подотчета UvedFL_GNI.rpt");

                        rd.Subreports["UvedFL_SumOKATO.rpt"].Database.Tables[0].SetDataSource(DS.Tables[3]);
                        rd.Subreports["UvedFL_SumOKATO.rpt - 01"].Database.Tables[0].SetDataSource(DS.Tables[3]);
                        rd.Subreports["UvedFL_SumOKATO.rpt - 02"].Database.Tables[0].SetDataSource(DS.Tables[3]);
                        logEvent.AppendText("установка датасета для подотчетов UvedFL_SumOKATO.rpt");

                        rd.Subreports["UvedFL_SumSrok.rpt"].Database.Tables[0].SetDataSource(DS.Tables[4]);
                        rd.Subreports["UvedFL_SumSrok.rpt - 01"].Database.Tables[0].SetDataSource(DS.Tables[4]);
                        rd.Subreports["UvedFL_SumSrok.rpt - 02"].Database.Tables[0].SetDataSource(DS.Tables[4]);
                        logEvent.AppendText("установка датасета для подотчетов UvedFL_SumSrok.rpt");

                        rd.Subreports["UvedFL_Sprav.rpt"].Database.Tables[0].SetDataSource(DS.Tables[5]);
                        rd.Subreports["UvedFL_Sprav.rpt - 01"].Database.Tables[0].SetDataSource(DS.Tables[5]);
                        rd.Subreports["UvedFL_Sprav.rpt - 02"].Database.Tables[0].SetDataSource(DS.Tables[5]);

                        logEvent.AppendText("установка датасета для подотчетов UvedFL_Sprav.rpt");

                        rd.Subreports["pd4new.rpt"].Database.Tables[0].SetDataSource(DS.Tables[6]);
                        logEvent.AppendText("установка датасета для подотчета pd4new.rpt");

                        rd.Subreports["UvedFL_Zayav.rpt - 01"].Database.Tables[0].SetDataSource(DS.Tables[7]);
                        rd.Subreports["UvedFL_Zayav.rpt - 01 - 01"].Database.Tables[0].SetDataSource(DS.Tables[7]);

                        logEvent.AppendText("установка датасета для подотчетов UvedFL_Zayav.rpt");
                    } 
                    catch (Exception e)
                    {
                        log.AppendText("ошибка set datasource в  report" + e.Message);
                    }
                    try
                    {

                        rd.ExportToDisk(ExportFormatType.PortableDocFormat, MainPath + "\\file" + (_numThread - 1) + "" + curNumRep + ".pdf");
                    }
                    catch (Exception e)
                    {
                        rd.Close();
                        rd.Dispose();
                        log.AppendText("ошибка exportToDisk " + e.Message);
                    }
                    logEvent.AppendText("ExportToDisk ");

                    int PageCnt = 0;
                    lock (rd)
                    {
                        PageCnt = rd.FormatEngine.GetLastPageNumber(new CrystalDecisions.Shared.ReportPageRequestContext());
                    }
                    cntPageBeg = PageCnt;
                    if (optSetPrinterDuplex == 2)
                    {
                        if (cntPD % 2 == 0)
                        {
                            cntPDPage = cntPD / 2;
                        }
                        else cntPDPage = cntPD / 2 + 1;
                        if (PageCnt % 2 == 0)
                        {
                            if (cntPDPage % 2 == 0)
                                PageCnt += cntPDPage - 1;

                            else
                                PageCnt += cntPDPage;
                        }
                        else
                        {
                            if (cntPDPage % 2 == 0)
                                PageCnt += cntPDPage;
                            else
                                PageCnt += cntPDPage - 1;
                        }
                        if (PageCnt % 2 == 0)
                            cntSheet = PageCnt / 2;
                        else
                            cntSheet = PageCnt / 2 + 1;

                    }
                    else
                        cntSheet = cntPageBeg;

                    // Read Image from Filesystem and add it to the Database.
                    FileStream fs = new FileStream(MainPath + "\\file" + (_numThread - 1) + "" + curNumRep + ".pdf", FileMode.Open, FileAccess.Read);
                    BinaryReader br = new BinaryReader(fs);
                    SaveImageToDB(fs, br, curNumRep, D270Cur);
                    SavecntPage(D270Cur, cntPageBeg, cntSheet, curNumRep);
                    logEvent.AppendText("конец фромирования отчета с номером  " + i);

                    fs.Close();
                    br.Close();
                    // --- delete pdf-file                    
                       f = new FileInfo(MainPath + "\\file"  + (_numThread - 1) + "" + curNumRep + ".pdf");
                       try
                       {
                           f.Delete();
                       }
                       catch (Exception e)
                       {
                           log.AppendText("ошибка удаления файла file" + curNumRep + ".pdf" + e.Message);
                       }
                   

                } 
                curNumPatch += 1;

            }     
        finally
            {
                rd.Close();
                rd.Dispose();
            }
            // before end of procedure 

        }
...
Рейтинг: 0 / 0
22.08.2012, 11:08
    #37925833
SanSYS
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
потоки с#, ошибка
Обязательно посмотрите в сторону тасков http://msdn.microsoft.com/ru-ru/library/system.threading.tasks.task.aspx
...
Рейтинг: 0 / 0
22.08.2012, 12:29
    #37926047
bazile
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
потоки с#, ошибка
GeneralMotorsфункциональность приложениея состоит в том что на основе некоего списка ID шников формируются кристаловские отчеты, сохраняющиеся потом в формате pdf и записывает эти пдф-ники в базу.
Это веб или desktop приложение?

GeneralMotorsОтчеты формируются в цикле поштучно. Минимум какого удалось добиться 1.2сек на один отчет - это много, потому как допустим список из 700000-8000000 шт . Запросов к БД мало, они пустяковые и выполняются за доли секунд.
В этом случае параллельное выполнение в самом деле поможет ускорить работу приложения.

GeneralMotorsприведу кусок кода формирущего непосредственно отчеты, мож подскажете где можно сократить.
Код ужасен. По сокращению советы здесь давать бессмысленно. Функцию - и скорее всего всё приложение - следует переписывать заново. Коротко пробегусь:
Вместо ArrayList используй System.Collections.Generic.List<int>. Ты же не на .NET 1.x сидишь, я надеюсь?

Переменная FileInfo f объявляется в самом начале, а используется в самом конце. Перенеси ее объявление к месту использования FileInfo f = new FileInfo(...)

В выражении new FileInfo(MainPath + "\\file" + (_numThread - 1) + "" + curNumRep + ".pdf") лучше использовать String.Format. Это сделает код более читабельным. Кроме того для сборки путей лучше использовать Path.Combine()

Для удаления файла нет нужды создавать объект FileInfo. Используй статический метод File.Delete(string)

Если имя функции начинается с Get, то я ожидаю что она _вернет_ нечто. У тебя же функции GetArrayD270 и GetTemplateReport() ничего не возвращают. Похоже они меняют какие-то instance поля класса. Подобный код тяжело поддерживать. Перепиши его.

Нет никакого смысла в поочередном вызове Close() и Dispose(). Они делают одно и то же.

Обращение к таблицам DataSet'a по индексу плохая идея в данном случае. Судя по коду всего их 8 штук. Через неделю ты не вспомнишь где что. Используй индексатор с именем таблицы - DS.Tables["Table1"]. Это чуть медленнее, но зато нагляднее.

SanSYSОбязательно посмотрите в сторону тасков
Хороший совет, но автору следует начинать с изучения основ .NET в целом и C# в частности.
...
Рейтинг: 0 / 0
22.08.2012, 13:51
    #37926231
SanSYS
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
потоки с#, ошибка
bazileSanSYSОбязательно посмотрите в сторону тасков
Хороший совет, но автору следует начинать с изучения основ .NET в целом и C# в частности.
Точно!
Автор, купи книгу CLR via C# (Рихтер)
...
Рейтинг: 0 / 0
22.08.2012, 14:45
    #37926369
GeneralMotors
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
потоки с#, ошибка
SanSYS,
информация полезная, надо почитать . Но мне не подходит - у меня FrameWork2.0
...
Рейтинг: 0 / 0
22.08.2012, 14:49
    #37926377
GeneralMotors
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
потоки с#, ошибка
bazile,

да, refactoring нужен безусловно.

Только переписывать так уж чтоб бы приложение работало с нужным объемом, а не сидеть на имеющейся производительности.
а для этого знаний не хватает ....
...
Рейтинг: 0 / 0
22.08.2012, 15:28
    #37926508
bazile
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
потоки с#, ошибка
GeneralMotorsТолько переписывать так уж чтоб бы приложение работало с нужным объемом, а не сидеть на имеющейся производительности.
а для этого знаний не хватает ....
В данном случае не согласен. Не имея базовых знаний за многопочность лучше не браться. Тебе нужно сначала отрефакторить код так чтобы функции, исполнение которых нужно распараллелить, как можно меньше (в идеале вообще) не зависели от instance переменных. Тогда переход на многопоточное выполнение пройдет более гладко.

Что касается знаний, то начинай с третьего издания CLR via C# (на русском CLR via C#. Программирование на платформе Microsoft .NET Framework 4.0 на языке C# ). По многопоточности для начала прочти Threading in C# .

И ты, кстати, не ответил какое у тебя приложение - ASP.NET или GUI? В данном обсуждении это имеет значение. Для веб-приложения многопоточная модель имеет свои особенности.
...
Рейтинг: 0 / 0
22.08.2012, 15:35
    #37926529
GeneralMotors
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
потоки с#, ошибка
bazile,

сорри, забыл, у меня обычное desctop приложение
спасибо за книги, качнул
...
Рейтинг: 0 / 0
22.08.2012, 15:43
    #37926556
bazile
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
потоки с#, ошибка
GeneralMotorsу меня обычное desctop приложение
Тогда надо сразу в форуме WinForms, .Net Framework вопрос задавать. Попросил модераторов перенести.
...
Рейтинг: 0 / 0
22.08.2012, 15:49
    #37926572
GeneralMotors
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
потоки с#, ошибка
bazile,

блин, не знал
...
Рейтинг: 0 / 0
Форумы / ASP.NET [игнор отключен] [закрыт для гостей] / потоки с#, ошибка / 12 сообщений из 12, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]