Deutsch
Germany.ruФорумы → Архив Досок→ Программирование

​Немножко вне рутины...

701  1 2 3 4 все
Murr патриот19.05.17 14:30
Murr
19.05.17 14:30 

Немножко вне рутины...

</p><blockquote style="">
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace A
{
    class A
    {
        StreamWriter sw = null;
        public StreamWriter Sw
        {
            get {
                if(sw == null)
                {
                    // get from class where instantiated/specified.
                }
                return sw;
            }
            set { sw = value; }
        }
    }


    class B1 : A
    {
        String b1 = "B1";
        public void GetResult()
        {            
            Sw.Write(b1);


            B2 b2 = new B2();
            b2.GetResult();
        }
    }


    class B2 : A
    {
        String b2 = "B2";
        public void GetResult()
        {
            Sw.Write(b2);
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            using (StreamWriter sw = new StreamWriter("Data.dat"))
            { 
                B1 b1 = new B1();
                b1.Sw = sw;
                b1.GetResult();
            }
        }
    }
}

</blockquote><p>

Что имеем? Имеем один базовый класс А и несчетное множество производных B*.

Существенно - классы B* между собой НЕ взаимодействуют - нет пересылки данных или передачи параметров, но один класс может инстанцировать другой и вызывать методы другого.


Классы B* выполняют какие-то действия (какие - не суть важно) и помещают результат в stream. Вид stream'а и что именно туда скидывается меня не интересует.


Меня интересует - можно ли в приведенном коде обеспечить чтобы B1 & B2 использовали один и тот же stream?

Чтобы было не слишком легко - несколько Б*шек будут работать параллельно - одним стреамом обойтись не получится - мне нужен именно доступ к тому где он задаn...


#1 
NightWatch коренной житель19.05.17 14:48
NightWatch
NEW 19.05.17 14:48 
в ответ Murr 19.05.17 14:30
можно ли в приведенном коде обеспечить чтобы B1 & B2 использовали один и тот же stream?

Ответ, по-моему, очевиден: нет.

#2 
Программист коренной житель19.05.17 15:05
NEW 19.05.17 15:05 
в ответ Murr 19.05.17 14:30
Существенно - классы B* между собой НЕ взаимодействуют - нет пересылки данных или передачи параметров, но один класс может инстанцировать другой и вызывать методы другого.

Что-то я не понял, если классы B* между собой не взаимодействуют, то как один класс может инстанциировать другой и вызывать его методы?


Меня интересует - можно ли в приведенном коде обеспечить чтобы B1 & B2 использовали один и тот же stream?
Чтобы было не слишком легко - несколько Б*шек будут работать параллельно - одним стреамом обойтись не получится - мне нужен именно доступ к тому где он задаn...

Делаешь фабрику стримов и пусть она принимает решение о том, создать новый стрим или вернуть один из существующих.

#3 
Murr патриот19.05.17 16:03
Murr
NEW 19.05.17 16:03 
в ответ NightWatch 19.05.17 14:48

Ответ, по-моему, очевиден: нет.

-----

Хммм... Я бы не был столь категоричен.

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


Одним из вариантов решения будет сделать поток статическим. Но этот вариант меня не устраивает,

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

Надо придумать что-то типа треад-статик вариабле... Что на 100% возможно.


Но там получается другая (см. внизу) сложность.


Изначально это делается чтобы сократить издержки на создание стреамов. Они - неприемлемо высокие.

Первоначально Я сделал пулл потоков и подставлял стреам из пула когда его запрашивали.

Относительно начальной схемы, где стреамы создавалось локально, все существенно ускорилось.

Пулл был рамером в 120 стреамов. Больше 240 - не выдерживала ОСь. Возможно, что можно что-то

подстроить (см Филес в конфиге), но проблема не в этом - там была однозадачная система. А мне сейчас

нужно иметь параллельность выполнения. При параллельном выполнении количество задействованных

стреамов очень быстро достигнет предела. Каким бы предел ни был. Т.е. это не вариант.


Так что остается только контролировать количество исполняемых треадов и гарантировать что

в треаде используется один стреам. И этот стреам надо как-то шарить между Бешками.


А упомянутая выше сложность заключается в том, что треад не умеет (ну или Я не умею) возвратить

стреам в пулл по завершении потока. А создавать его каждый раз внутри потока - накладно...


#4 
Murr патриот19.05.17 16:25
Murr
NEW 19.05.17 16:25 
в ответ Программист 19.05.17 15:05

если ... то

-----

Ну давай напишем - ограниченно взаимодействуют - могут вызвать единственный хорошо известный метод без параметров.

Ничего добавить Я не могу - Бешки - не рукотворные и имеют жесткие ограничения.

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

Чтобы было совсем весело - подозреваю, что мне еще и инстансы Бешек надо будет кешировать... смущ


Делаешь фабрику стримов

-----

У меня есть пулл стреамов.

Потому что создавать их дорого.

Но пулл, к сожалению, не может принимать подобные решения.

Можно написать менеджера.

Примерно так, как сделано в Main - b1.Sw = sw; - но это - внешнее управление.

Мне нужно, чтобы эту задачу решал код в инстансе А, который "НЕ знает" кто пытается получить доступ к стреаму, но "знает", при отсутствии стреама инстанциация производится где-то внутри метода другой Бешки у которой есть нужный стреам. Вот до него мне и надо добраться.


Как-то так.

#5 
NightWatch коренной житель19.05.17 18:19
NightWatch
NEW 19.05.17 18:19 
в ответ Murr 19.05.17 16:03, Последний раз изменено 19.05.17 18:24 (NightWatch)
Существенно - классы B* между собой НЕ взаимодействуют - нет пересылки данных или передачи параметров,

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

А

public StreamWriter Sw
{
    get {
        if (sw == null) {
          // get from class where instantiated/specified.
        }
        return sw;
    }
    set {
        sw = value;
    }
}

исключает контроль над используемым потоком: неизвестно как и откуда getter берет поток, а setter вообще позволяет вызывающему коду подсунуть свой.

#6 
Murr патриот19.05.17 19:48
Murr
NEW 19.05.17 19:48 
в ответ NightWatch 19.05.17 18:19

реализация классов тебе не доступна

-----

Доступна, но изменять ее Я хоть и не не могу, но очень сильно не хочу.

Бишки - классы генерируемые для Т4-шаблонов - т.е. при крайней необходимости добавить - можно, но это ручная работа и делать ее не хочется.


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

-----

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

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


неизвестно как и откуда getter берет поток

-----

КАК - неизвестно - это и есть мой вопрос, а ОТКУДА - вполне известно - это тот же поток, который передан Б1 и лежит в его инстансе. Вопрос - как добраться до этого инстанса в указанных ограничениях?


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

#7 
  moose свой человек19.05.17 23:23
NEW 19.05.17 23:23 
в ответ Murr 19.05.17 14:30, Последний раз изменено 19.05.17 23:25 (moose)

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

Но не лучше ли было бы без никакого описания Вашего "дизайна", который Вы не можете заставить работать, описать просто и понятно Вашу изначальную проблему? Думаю, если Вам удастся ее четко сформулировать, то и решение Вы сами увидите тотчас. Или кто-то из публики его сможет Вам подсказать.

Вам нужно создать thread safe stream, или что-то еще?

#8 
AlexNek патриот20.05.17 14:03
AlexNek
NEW 20.05.17 14:03 
в ответ Murr 19.05.17 19:48
надо будет каждый раз помнить об параметре

Без изменения архитектуры будешь только заниматься изготовлением костылей. Очень нехорошо передавать поток через проперть.

Даже имена и то странные - void метод начинается с "Гет".


А пока следующее предложение.

Делаем "потоковый записыватель" с очередью заданий. Туда поступают "Бэшки" в требуемом порядке записи (накидал и "забыл"). Затем Бэшки выбираеются из очереди и передаеются врапперу записи, который может залочить поток и записать Бэшку в поток. И так повторяется пока все Бэшки в очереди не закончатся.

Ну а как паралелить записыватели - нужно знать задачу.

#9 
Murr патриот22.05.17 11:19
Murr
NEW 22.05.17 11:19 
в ответ AlexNek 20.05.17 14:03

Туда поступают "Бэшки" в требуемом порядке записи

-----

Если бы Я мог перевести все в список - вопрос бы не возникал.

Пока же получается так - надо записать часть из А, затем записать Б, в Б может быть инстанцировано и выполнено С, затем снова фрагмент Б и в конце еще фрагмент А.

Изменить порядок вызовов или сегментации - увы, не дано...


Даже имена и то странные - void метод начинается с "Гет".

-----

Ну писал на коленке, т.е. непосредственно на Германке - мог и ошибит'ся.

#10 
Murr патриот22.05.17 11:25
Murr
NEW 22.05.17 11:25 
в ответ Murr 19.05.17 14:30

Поменял пока так:


using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ThreadStaticTest
{
class A
{
[ThreadStatic]
static StreamWriter sw = null;
public StreamWriter Sw
{
get
{
if (sw == null)
{
// get from class where instantiated/specified.
throw new Exception("Output stream is null or not specified.");
}
return sw;
}
set { sw = value; }
}
}


class B1 : A
{
String b1 = "B1";
public void GetResult()
{
Sw.Write(b1);


B2 b2 = new B2();
b2.GetResult();
}
}


class B2 : A
{
String b2 = "B2";
public void GetResult()
{
Sw.Write(b2);
}
}

class Process
{
static int threads = 1;

public void Execute()
{
Thread newThread = new Thread(new ThreadStart(this.Generate));
newThread.Name = threads.ToString();
newThread.Start();
}

private void Generate()
{
using (StreamWriter sw = new StreamWriter("Data_" + threads.ToString() + ".dat"))
{
B1 b1 = new B1();
b1.Sw = sw;
b1.GetResult();
}
}
}

class Program
{
static void Main(string[] args)
{
Thread.CurrentThread.Name = "Main";

Process p = new Process();
p.Execute();
}
}
}




Вроде работает. По крайней мере по ексептиону пока не вылетает.

Многопоточку - пока не гонял - надо сделать более-мение нормальный "источник" инстансов Б1 и прикрутить пулл для стреамов.


Будут какие замечания/пожелания/советы?

#11 
Murr патриот22.05.17 11:43
Murr
NEW 22.05.17 11:43 
в ответ moose 19.05.17 23:23

Вы всегда странным образом формулируете Вашу проблему.

------

Ну что тут поделать - Я таки ДУМАЮ странным образом. Ну а как думаю - так и формулирую.

Я знаю, что думать так как думаю Я - довольно сложно... но(!), как показывает практика, довольно эффективно.

По крайней мере, когда так думает команда - все получается довольно гладко...


Вы уже вроде бы как и решение придумали, и считаете, что нужно решить именно так.

-----

Замени "нужно" на "можно" и Я с тобою соглашусь.


Вам нужно создать thread safe stream, или что-то еще?

-----

Мне нужно шарить стреаm между объектами создаваемыми в потоке. Пока - в том же потоке.

Но вполне возможно, что все сильно-сильно ухудшится и мне нужно будет шарить стреам из внешнего, по отношению к потоку выполнения, пула в пределах потока выполнения между объектами создаваемыми в другом/других потоках.

Понимаю, что звучит сложно и неприятно - но, увы, более внятно пока не формулируется.

#12 
AlexNek патриот22.05.17 19:04
AlexNek
NEW 22.05.17 19:04 
в ответ Murr 22.05.17 11:19
Если бы Я мог перевести все в список - вопрос бы не возникал.

Тогда я не понимаю принципа записи. Если каждый пишет когда хочет, то в файле или бардак или множество мелких записей.

#13 
Murr патриот22.05.17 20:57
Murr
NEW 22.05.17 20:57 
в ответ AlexNek 22.05.17 19:04

Если каждый пишет когда хочет, то в файле или бардак или множество мелких записей.

-----

Каждый пишет когда его "очередь" писать.



    class B1 : A
    {
        String b1 = "B1";
        public void GetResult()
        {            
            Sw.Write(b1 + " 1"); // pishem
 
            B2 b2 = new B2();
            b2.GetResult(); // pishem drugoe

            Sw.Write(b1 + " 2"); // snova pishem
        }
    }



Нормально там все пишется. Пока по крайней мере проблем не видел.


Что меня сейчас интересует - как это будет работать в случае когда класс инстанцируется в другом потоке... Жаль - времени потестить нет - снова надо монстром заниматься...

#14 
AlexNek патриот22.05.17 21:16
AlexNek
NEW 22.05.17 21:16 
в ответ Murr 22.05.17 20:57
как это будет работать в случае когда класс инстанцируется в другом потоке

То бишь B2 b2 = new B2(); располагается не в функции GetResult(), а еще где то?


#15 
Murr патриот22.05.17 23:27
Murr
NEW 22.05.17 23:27 
в ответ AlexNek 22.05.17 21:16

а еще где то?

-----

Угу... в другом потоке. Предположительно - фабрика, выполняемая где-то в основном потоке...

Не понимаю какая у него будет треад-статик статик переменная - потока создания или потока выполнения... Надо тестить...

#16 
AlexNek патриот22.05.17 23:39
AlexNek
NEW 22.05.17 23:39 
в ответ Murr 22.05.17 23:27
Угу... в другом потоке.

А как тогда известно "когда готово"? Это то ведь GetResult должна знать.

#17 
Murr патриот22.05.17 23:45
Murr
NEW 22.05.17 23:45 
в ответ AlexNek 22.05.17 23:39

Инстанцирование - там, выполнение - тут.

Вот как завершится GetResult - так и готово.

#18 
AlexNek патриот23.05.17 00:14
AlexNek
NEW 23.05.17 00:14 
в ответ Murr 22.05.17 23:45
B2 b2 = new B2();
b2.GetResult(); // pishem drugoe

то есть обе строки в другом месте и ты туда не хочешь/не можешь передать поток?

#19 
Murr патриот23.05.17 11:08
Murr
NEW 23.05.17 11:08 
в ответ AlexNek 23.05.17 00:14

то есть обе строки в другом месте и ты туда не хочешь/не можешь передать поток?

-----

IB2 b2 = Program.Factory.Create("B2"); // nado napisat'
b2.GetResult(); // pishem drugoe

И Я не хочу передавать туда поток в ручную - слишком много раз это надо делать и это совершенно никак не относится к решаемой этим кодом задаче.

Но Я хочу, чтобы b2.GetResult() получила доступ к стреаму в потоке выполнения и сделала это без дополнительных телодвижений с моей стороны.

Желательно - и без больших накладных расходов.


У меня вообще есть желание видеть это в одну строку. Примерно так

GetResult("B2");

Возможно, что это и будет решением.


П.С. Как-то оно близко коррелирует с твоими запросами к загрузке плагинов.

#20 
1 2 3 4 все