Конференция "Начинающим" » Помогите написать работу с потоком [D7]
 
  • Kirill © (22.08.17 11:31) [0]
    Добрый день.
    Есть программа работы с кассовым аппаратом. В отдельном модуле реализовано хранение чеков в БД, в отдельном работа с web-сервисом (обмен json-данных) с 1С.

    Необходимо написать отправку данных в 1С в отдельном потоке. Программа должна делать выборку из БД данных, которые не отправлены и отправлять в 1С. В случае успешной отправки помечать запись как отправленную. К сожалению, у меня совсем не получается постичь работу в Delphi с потоками, поэтому пишу в эту конференцию.

    Вопросы по теме:
    1. Как лучше делать выборку неотправленных  данных? По одной записи или все неотправленные и все отправлять? Чтобы фризов в основной программе не было.
    2. Как правильно описать Объект потока? В основном потоке уже есть открытое соединение с БД. Надо будет создавать новое соединение?
    3. Как правильно вызвать этот поток? При запуске программы (открытии основной формы) или по таймеру запускать (например каждую минуту)?

    Delphi 7. БД: Firebird 2.5.7 embed. WS: Synapse и lkJSON.
  • KilkennyCat © (22.08.17 12:20) [1]

    > Чтобы фризов в основной программе не было.

    вроде как, эту проблем уже решает отдельный поток
    1. да как угодно. если объем данных небольшой, соединение устойчивое - все сразу.
    2. если отправлять по одной записи, то к бд вообще нет смысла обращаться, данные уже есть (внесение в бд же ими делается)
    3. если отправлять по одной записи, то сразу при появлении данных. если все сразу - то по завершении кассовой смены.
  • KilkennyCat © (22.08.17 12:21) [2]
    а еще это может регламентироваться законодательством, сразу или не сразу отправлять.
  • Kirill © (22.08.17 13:26) [3]
    Не, данные по законодательству отправляются самим аппаратом. А вот в 1С, по-хорошему, надо сразу видеть что оплатили, а что еще нет. А так как есть точки удаленные с нестабильным интернетом, надо предусмотреть что когда чек был пробит инета не было, а потом пытаться, пытаться, пытаться отправить.
  • Kirill © (22.08.17 15:27) [4]
    Можно простенький примерчик, в какой момент получать данные, в какой отправлять данные, получать ответ от веб-сервиса, записывать флаг об успешной отправке и, главное, в какой момент вызывать синхронизации с основным потоком, чтобы зависаний не было.
  • ухты © (22.08.17 16:21) [5]
    Synapse разве не умеет асинхронно работать?
  • Kirill © (22.08.17 16:34) [6]
    Нет. ICS асинхронно работает.
    Помимо этого хочу разобраться на небольшом но осязаемом примере как правильно использовать потоки.
  • kilkennycat © (22.08.17 17:56) [7]

    > Можно простенький примерчик, в какой момент получать данные,
    >  в какой отправлять данные, получать ответ от веб-сервиса,
    >  записывать флаг об успешной отправке и, главное, в какой
    > момент вызывать синхронизации с основным потоком, чтобы
    > зависаний не было.

    Это не простенький примерчик. И все эти моменты определяет программист. Про зависания вообще непонятно.
    Имеет смысл сначала всё-таки прочитать книжки по делфи, коих множество, и в коих есть простенькие примерчики отдельных задач. И  тогда вопрос либо отпадет, либо трансформируется в что-то более конкретное.
    А вот если бы я писал эту программу, то делал бы ее по ТЗ заказчика.
  • Kirill © (22.08.17 18:00) [8]

    procedure SendLocalDataToServer;
    var
     sthr : TSendThread;
    begin
     //
     sthr := TSendThread.Create(True);
     sthr.fhttp := http;
     sthr.Priority := tpLower;
     sthr.FreeOnTerminate := True;
    end;

    { TSendThread }

    procedure TSendThread.Execute;
    var s : string;
    begin
     inherited;
     while True do begin
       if Terminated then Break;
       if not DM.SelectDataForSend then begin
         Terminate;
         Break;
       end;
       DM.ibqryThread.First;
       if fhttp.PostPayData(
         DM.ibqryThread.FieldByName('chid').AsInteger,
         DM.ibqryThread.FieldByName('cheque_type').AsInteger,
         DM.ibqryThread.FieldByName('cheque_time').AsDateTime,
         DM.ibqryThread.FieldByName('aw_date').AsDateTime,
         DM.ibqryThread.FieldByName('client').AsString,
         DM.ibqryThread.FieldByName('aw_code').AsString,
         DM.ibqryThread.FieldByName('department').AsInteger,
         DM.ibqryThread.FieldByName('vat_type').AsInteger,
         DM.ibqryThread.FieldByName('quantity').AsFloat,
         DM.ibqryThread.FieldByName('price').AsFloat,
         DM.ibqryThread.FieldByName('summ').AsFloat,
         DM.ibqryThread.FieldByName('vatsumm').AsFloat,
         DM.ibqryThread.FieldByName('summ1').AsFloat,
         DM.ibqryThread.FieldByName('summ2').AsFloat,
         DM.ibqryThread.FieldByName('summ3').AsFloat,
         DM.ibqryThread.FieldByName('summ4').AsFloat,
         DM.ibqryThread.FieldByName('vat18').AsFloat,
         DM.ibqryThread.FieldByName('vat10').AsFloat,
         DM.ibqryThread.FieldByName('vat0').AsFloat,
         s) then begin
         // TODO
         // write code for mark this cheque as posted on server
       end;
     end;
    end;


    Может подскажете на таком примере правильное направление мысли?
  • KilkennyCat © (22.08.17 21:11) [9]
    здесь нет мысли ))) лишь небезопасная отправка кучки полей через http-post, и без примера обработки ошибок.
  • Kirill © (23.08.17 08:58) [10]
    Т.е. простенького примера (можно из комментариев) какой структуры вы бы написали объект потока, в каких процедурах и в какой момент делать выборку данных, отправку в 1с, запись в бд и вызов встроенных процедур самого потока в конференции новичков не дождешься? Н-да... страшно представить чтобы в остальных конференциях сказали и куда послали...
    Спасибо, что не отказали.
  • rrrrrrr © (23.08.17 09:20) [11]
    по коду:
    непонятно используется ли отдельная сессия для запроса из потока.

    по дизайну:
    эй, поток, я вон там оставил для тебя какие-то штуки.
    у тебя в юзез мой дм, плюс ты умный, так что сходи туда возьми все что надо (ты знаешь) и сделай что мне надо.
  • Kirill © (24.08.17 00:57) [12]
    Зря вы так... Спасибо брату, что нашел время и помог мне. Я, конечно, до сих пор не понял как с ним работать, но с его помощью и методом тыка написал такой код, который работает.

    constructor TSendThread.Create;
    begin
     fhttp := THttpService.Create;
     fTimeout := 1000;
     inherited Create(False);
    end;

    procedure TSendThread.SendData;
    var s : string;
    begin
     if not DM.SelectDataForSend then begin
       fTimeout := 5000;
     end
     else begin
       fTimeout:= 1000;
       with DM.ibqryThread do begin
         First;

         if fhttp.PostPayData(
           FieldByName('chid').AsInteger,
           FieldByName('cheque_type').AsInteger,
           FieldByName('cheque_time').AsDateTime,
           FieldByName('awbdate').AsDateTime,
           FieldByName('client').AsString,
           FieldByName('awbcode').AsString,
           FieldByName('department').AsInteger,
           FieldByName('vat_type').AsInteger,
           FieldByName('quantity').AsFloat,
           FieldByName('price').AsFloat,
           FieldByName('summ').AsFloat,
           FieldByName('vatsumm').AsFloat,
           FieldByName('summ1').AsFloat,
           FieldByName('summ2').AsFloat,
           FieldByName('summ3').AsFloat,
           FieldByName('summ4').AsFloat,
           FieldByName('vat18').AsFloat,
           FieldByName('vat10').AsFloat,
           FieldByName('vat0').AsFloat,
           s) then begin
           DM.SetChequePosted(FieldByName('chid').AsInteger);
         end;
       end;
     end;
    end;

    procedure TSendThread.Execute;
    begin
     while not Terminated do begin
       Synchronize(SendData);
       Sleep(fTimeout);
     end;
    end;


    Я не просил за меня написать код. Я просил помочь разобраться со структурой вызовов: где что и когда вызывать... В этом без брата я бы не разобрался.

    Я от сообщества ожидал, что-то типа такого:

    procedure TThread.SendData;
    begin
    // выборка данных для отправки.
    // отправка данных
    // если отправка успешна, то фиксируем в бд
    end;

    procedure TThread.Execute;
    begin
     while not Terminated do begin
       Syncronize(SendData);
       Sleep(1000);
     end;
    end;



    Что сложного написать тому, кто это знает и главное понимает, эти 10 строк. Я тоже это знаю, и программировать на каких-то языках могу очень сложные приложения, а на каких-то только понять, что писал автор, но вот никак не могу усвоить в какой последовательности надо программировать работу с потоками в Delphi. И пример про сортировку разобрал из поставки, но как применить его конкретно на моем примере так и не понял.

    Спасибо. Вопрос закрыт
  • Германн © (24.08.17 01:45) [13]

    > Kirill ©   (22.08.17 16:34) [6]
    >
    > Нет. ICS асинхронно работает.

    Хм. ICS действительно работает как правило асинхронно. В это одна из главных её особенностей (но и синхронно тоже умеет). Но при чем тут ICS?
  • KilkennyCat © (24.08.17 07:25) [14]

    > Kirill ©
    > Что сложного написать тому, кто это знает и главное понимает,
    >  эти 10 строк.

    они есть практически в любой книжке. что сложного в чтении книжки? Например, у Тейксейры и Пачеко https://www.for-stydents.ru/informatika/delphi/uchebniki/delphi-5-rukovodstvo-razrabotchika-tom-1-osnovnye-metody-i-tehnologii-programmirovaniya.html есть даже "Многопоточный доступ к базе данных". Читали?
    И прочитайте https://www.opennet.ru/docs/RUS/smart_question/
  • Юрий Зотов © (24.08.17 07:25) [15]
    > Kirill ©   (24.08.17 00:57) [12]

    > Вопрос закрыт


    Вряд ли вопрос закрыт. Дело в том, что в такой редакции второй поток не имеет никакого смысла. Смотрим метод Execute:

    procedure TSendThread.Execute;
    begin
     while not Terminated do begin
       Synchronize(SendData);
       Sleep(fTimeout);
     end;
    end;


    Видим, что:

    1. Метод SendData вызывается через метод Synchronize - то есть, метод SendData все равно будет выполнен в главном (а не во втором) потоке.

    2. Sleep - в данном случае не дает ничего, кроме тормозов (ну разве что разгружает процессор, больше никакого прока от него здесь нет).

    3. Больше ничего второй поток не делает. Какой же тогда в нем смысл? Без него все будет работать точно так же.
  • rrrrrrr © (24.08.17 08:40) [16]
    плюс снова непонятно есть ли у брата отдельная от основной сессия с бд.
  • Kirill © (24.08.17 08:49) [17]

    > они есть практически в любой книжке. что сложного в чтении
    > книжки?

    А это из разряда смотрим в книгу, видим фигу. Это проблема моего мышления. Пока я не могу представить в голове, я этого не понимаю и не запоминаю. Я так с фуаном мучался в универе. Я ж говорю, и примеров полно и код рабочий был по потокам, ну не могу понять как он работает. Ответы Юрия тому пример.


    > Метод SendData вызывается через метод Synchronize - то есть,
    >  метод SendData все равно будет выполнен в главном (а не
    > во втором) потоке.

    Т.е. вызывать надо без него?


    > Sleep - в данном случае не дает ничего, кроме тормозов (ну
    > разве что разгружает процессор, больше никакого прока от
    > него здесь нет)

    Sleep не делает DDOS атаку на web-сервис 1С. Т.е. он отправляет неотправленные чеки с периодичностью каждую секунду, а если в последний раз не было ничего на отправку, то ждет уже 5 сек.

    > Больше ничего второй поток не делает. Какой же тогда в нем
    > смысл? Без него все будет работать точно так же.

    Смысл в том, чтобы пользователь продолжал работать с кассой, а сама программа отправляла подтверждения оплат не блокируя интерфейс.


    > плюс снова непонятно есть ли у брата отдельная от основной
    > сессия с бд.

    На счет его я не знаю, какая у него структура БД, а у меня нет. Надо новую? А если FB Embeded?
  • rrrrrrr © (24.08.17 08:52) [18]
    Sleep не делает DDOS

    вотэтоповорот. кто бы мог подумать.

    На счет его я не знаю, какая у него структура БД, а у меня нет. Надо новую? А если FB Embeded?

    уже пофик.
  • rrrrrrr © (24.08.17 08:55) [19]
    Смысл в том, чтобы пользователь продолжал работать с кассой, а сама программа отправляла подтверждения оплат не блокируя интерфейс.

    без этого потока все будет точно так же. тютя в тютю.
    даже немного более быстрее и менее тормознуто.
 
Конференция "Начинающим" » Помогите написать работу с потоком [D7]
Есть новые Нет новых   [118460   +14][b:0][p:0.001]