Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   ProcessMessages (https://javascript.ru/forum/misc/1609-processmessages.html)

Autosof 26.08.2008 15:00

Цитата:

Сообщение от Kolyaj (Сообщение 4999)
Ну если по теме: в JavaScript функции -- объекты первого типа

Это явно из какой-то теории. По сему вопрос - какие типы ещё бывают и чем отличаются (кроме номеров)? Ну это так, из спортивного интереса.

Цитата:

Сообщение от Kolyaj (Сообщение 4999)
... открывает такие возможности написания простого и лаконичного кода, который ObjectPascal'ю даже не снился.

Цены бы Javascript не было, если бы можно было реализовать то с чего тема начата была...
А так остается только приспосабливаться к особенностям языка.

Почемучкин 02.08.2011 06:55

Мнэээ... наткнулся тут на эту тему. И чисто для справки тем кто как и я будут читать архив, вставлю, что я пока в JavaScript не большой специалист, но в Delphi тоже можно передавать функции как параметры - по ссылке, и возвращать как результат работы. Более того, есть даже возможность описывать типы как функции. Например можно сделать массив или список функций.
И еще - почитал тут в инете, что вроде можно в JavaScript использовать window.postMessage, так что какая-никакая обработка сообщений в нем есть и соответственно это касается вопроса топикстартера. Он не про многопоточность спрашивал, а про передачу управления в очередь обработки сообщений, пока происходит ожидание - заметьте, что это именно в однопоточном приложении. И насколько я понял - если пользоваться очередью сообщений, написав свой ProcessMessages, то только в IE скрипт будет блокироваться, а в других браузерах будет работать асинхронно.

Владимир_Фомин 06.09.2014 15:57

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

Очень хотелось бы сделать, чтобы браузер не зависал при длительном вычислении, то есть чтобы рекурсивная функция длительного перебора не препятствовала другим процессам. Очень хотелось бы найти аналог Application.ProcessMessages в javascript, который позволял бы, например, идти часам во время работы программы.

Браузер Firefox зависнет на целую минуту в Судоку-онлайн для примера 3, пока программа сделает 3 миллиона переборов, а в для примера 46 зависнет на целых 2 минуты, пока программа сделает 9 миллионов переборов.

Вот здесь добавил часы на страничку
sudokut.htm
, и если вы попробуете решить пример 3 или пример 46, то увидите, что во время работы программы часы остановятся.

Скрипт программы.

Подвешивает браузер вот этот код.

function recfrugal(k)
{
  var i;
  var j; 
  var t;
  var q;
  if (k == 82)
  {
    u++;
    for (i = 1; i <= 81; i++) z[i][u] = s[i]
  }
  if ((k <= 81) && (u < 10))
  {
    if ((w[k] == 0) || (w[k] == 1)) recfrugal(k+1);
    if (w[k] > 1)
    {
      for (t = 1; t <= w[k]; t++)
      {
        q = true;
        for (j = 1; j <= 20; j++) if (b[k][t] == s[m[k][j]]) q = false;
        if (q == true)
        {
          s[k] = b[k][t];
          c++;
          recfrugal(k+1);
        }
      }
      s[k] = 0;
      c++;
    }
  }  
}


Что конкретно надо добавить в код программы, чтобы зависание браузера во время длительных вычислений не происходило?

В Паскале (Лазарусе) достаточно было для этого дописать в код функции одну только строчку Application.ProcessMessages

Цитата:

procedure recgen(k: integer; h: integer; g: integer);
var
i: integer;
j: integer;
t: integer;
q: boolean;
begin
Application.ProcessMessages;
if k = size*size + 1
then
begin
u0:=u0+1;
Form2.EditNumberOfSolutions.Text:=IntToStr(u0);
randomize;
randomfield;
for i:=1 to size*size do
if r[i]<=h
then gen[i]:=sg[i]
else gen[i]:=0;
rank(g);
end;
if (k<=size*size) and (stop=false) and (u<>g)
then
begin
randomize;
randomingnumber;
for t := 1 to size do
begin
q := true;
for j := 1 to mc[k] do
if y[t] = sg[m[k, j]]
then q := false;
if (q = true)
then
begin
sg[k] := y[t];
recgen(k+1, h, g);
end;
end;
sg[k] := 0;
end;
end;

А что является аналогом Application.ProcessMessages в javascript?

Aetae 06.09.2014 16:09

JS однопоточный язык. Нет в нём изначально никаких "других" процессов. Остановка - есть остановка всего на странице.

Современное решение: web worker. Он создаёт отдельный поток из отдельного скрипта, что общается с основным потоком сообщениями.
По старинке: дробить вычисления setTimeout'ами.

kobezzza 06.09.2014 22:27

Я как раз сейчас этим занимаюсь в рамках Collection 5.2 (в сообщение по ссылке есть ссылка на демо видео, где создано 50 потоков с разными приоритетами, каждый из которых считает 1кк итераций), где потоки реализуются с помощью прерываний (yield) функций и планировщика, т.е. модель такая же как и в потоках на одноядерных процах.

Цитата:

Современное решение: web worker.
К сожалению решение довольно однобокое, т.к. с одной стороны - это не JS, а некоторая приблуда браузера, а также очень много ограничений (в том числе на количество создаваемых потоков в рамках домена), да и сама операция создания довольно дорогая.

Aetae 06.09.2014 22:38

Цитата:

Сообщение от kobezzza (Сообщение 329270)
К сожалению решение довольно однобокое

Справедливо, тем не менее большинство обычных проблем решает.
То что делаешь ты - крутотень, но весьма специфическая.)

kobezzza 06.09.2014 22:44

Цитата:

Сообщение от Aetae (Сообщение 329274)
То что делаешь ты - крутотень, но весьма специфическая.)

На самом деле нет, как сделаю релиз, то сможешь убедится: я сделаю наглядную демку, в которой можно будет пощупать и увидеть, что всё супер просто.

// Простая синхронная итерация
$C([...]).forEach(function () {
    ...
});

// Итерация в потоке
$C([...]).forEach(function () {
    ...
}, {thread: true});


Главный плюс таких потоков, что по сути, мы остаёмся в главном потоке и у нас спокойный доступ к DOM, переменным замыкания и т.д. хотя с другой стороны это и минус - т.к. можно выстрелить себе в ногу.

К сожалению самый главный недостаток этого подхода - это необходимость поддержки генераторов, а она есть только в Хроме и ФФ, но обещали вкрутить в ИЕ12, а про Сафари я даже не знаю, надо будет посмотреть, но в ноде я уже планирую полноценное внедрение этой технологии.

Владимир_Фомин 07.09.2014 20:05

Цитата:

Сообщение от Aetae (Сообщение 329222)
По старинке: дробить вычисления setTimeout'ами.

Вот именно! Очень хотелось бы без всяких премудростей setTimeout'ами добиться того, чтобы браузер не зависал.

Но куда вставлять этот setTimeout, если функция, вызывающая зависание браузера, рекурсивная?

function recfrugal(k)
{
  var i;
  var j;
  var t;
  var q;
  if (k == 82)
  {
    u++;
    for (i = 1; i <= 81; i++) z[i][u] = s[i]
  }
  if ((k <= 81) && (u < 10))
  {
    if ((w[k] == 0) || (w[k] == 1)) recfrugal(k+1);
    if (w[k] > 1)
    {
      for (t = 1; t <= w[k]; t++)
      {
        q = true;
        for (j = 1; j <= 20; j++) if (b[k][t] == s[m[k][j]]) q = false;
        if (q == true)
        {
          s[k] = b[k][t];
          c++;
          recfrugal(k+1);
        }
      }
      s[k] = 0;
      c++;
    }
  } 
}


Если заменить рекурсивный вызов recfrugal(k+1); вот так:
setTimeout(function() { recfrugal(k+1) }, 1000);

то ничего не получается, так как она просто будет через него перескакивать, корректного результата не получится.

Aetae 07.09.2014 20:24

Переписать рекурсию на циклы.

kobezzza 12.09.2014 16:53

Оставлю тут ссылку: реализация потоков в Collection 5.2


Часовой пояс GMT +3, время: 07:33.