powered by simpleCommunicator - 2.0.59     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / ASP.NET [игнор отключен] [закрыт для гостей] / потоки с#, ошибка
12 сообщений из 12, страница 1 из 1
потоки с#, ошибка
    #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
потоки с#, ошибка
    #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
потоки с#, ошибка
    #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
потоки с#, ошибка
    #37925833
Фотография SanSYS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Обязательно посмотрите в сторону тасков http://msdn.microsoft.com/ru-ru/library/system.threading.tasks.task.aspx
...
Рейтинг: 0 / 0
потоки с#, ошибка
    #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
потоки с#, ошибка
    #37926231
Фотография SanSYS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
bazileSanSYSОбязательно посмотрите в сторону тасков
Хороший совет, но автору следует начинать с изучения основ .NET в целом и C# в частности.
Точно!
Автор, купи книгу CLR via C# (Рихтер)
...
Рейтинг: 0 / 0
потоки с#, ошибка
    #37926369
GeneralMotors
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SanSYS,
информация полезная, надо почитать . Но мне не подходит - у меня FrameWork2.0
...
Рейтинг: 0 / 0
потоки с#, ошибка
    #37926377
GeneralMotors
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
bazile,

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

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

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

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

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

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


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