IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.
Mezi 13:00 až cca 16:00 proběhne odstávka sítě z důvodu aktualizace. Web bude po celou dobu nedostupný.
Avatar
Petr Nymsa
Tvůrce
Avatar
Petr Nymsa:28.5.2013 19:39

Už se obracím na vás. Máte někdo zkušenosti s novým asynchroním programováním přes acync a await. Novinka C# 5.

Jde mi o jedno. Tvořím narychlo (ano narychlo, deadline je nebezpečně blízko) aplikaci pro Windows 8 a jedním důležitým prvkem je nezamrzání UI když se něco děje.

U mě se děje generování ASCII. Z nějakého důvodu mi vlákno s UI zamrzne i když by nemělo ("nemělo"). Podmínkou je aby UI vypadalo že stále běží v pohodě i když se v pozadí něco děje. Stále můžu přejíždět přes tlačítka, která se animují apod. Pošlu ústřižky kódu

Zde volám metodu která generuje ASCII -> je zavolána asynchronně. Po jejím dokončení nastavím nový text.

string result = await manager.GenerateAsciiText(file);
manager.HTML = result;

Vlastní metoda pro generování. Kód je s prominutím prasárna. Generuje to špatně, každopádně ve WinForm to i celkem běhá. Až vyřeším UI přepíšu to.

public async Task<string> GenerateAsciiText(StorageFile file)
      {
          ascii = new StringBuilder();

          using(IRandomAccessStream stream =await file.OpenAsync(FileAccessMode.Read))
          {
              wb = await new WriteableBitmap(1, 1).FromStream(stream);
          }
          for (int h = 0; h < wb.PixelHeight - Size; h += Size)
          {
              for (int w = 0; w < wb.PixelWidth - Size; w += Size)
              {

                  int color = 0;
                  for (int x = 0; x < Size; x++)
                  {
                      for (int y = 0; y < Size; y++)
                      {
                          Color pixelColor = wb.GetPixel(w + y, h + x);
                          color += (pixelColor.R + pixelColor.G + pixelColor.B) / 3;
                      }
                  }

                  color = color / (Size * Size);
                  Color grayColor = Color.FromArgb(255, (byte)color, (byte)color, (byte)color);

                  ascii.Append(getAsciiChar(grayColor.A));


              }
              ascii.Append(Environment.NewLine);
          }

          return ascii.ToString();
      }

StorageFile = soubor s obrázkem
IRandomAccessStre­am = rohraní pro čtená datového toku
WriteableBitmap - bitmapa která jde upravovat. Používám cizí knihovnu která doplnuje metodu GetPixel, SetPixel,...

Vím že je to i celkem pomalý, ale to není důvod aby to zamrzlo při obrázku 150px * 150px.

Vlákno se má oddělit a UI má běžet stále stejně.

Nějaké info http://blog.imp.cz/…-jazyka-C-50

http://vimeo.com/57608362 - video - ukázka synchroního a asynchroního chování.

Děkuju za rady ! :) A klidně mě umlaťte :D.

Odpovědět
28.5.2013 19:39
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Petr Nymsa
Tvůrce
Avatar
Petr Nymsa:29.5.2013 11:08

Dokázal by někdo poradit ?

Nahoru Odpovědět
29.5.2013 11:08
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
David Hartinger
Vlastník
Avatar
Odpovídá na Petr Nymsa
David Hartinger:29.5.2013 12:28

Tyto nové metody neznám, ale určitě je v WPFku něco jako ve WinForms Beckground worker, nebo snad ne?

Nahoru Odpovědět
29.5.2013 12:28
New kid back on the block with a R.I.P
Avatar
David Hartinger
Vlastník
Avatar
Odpovídá na Petr Nymsa
David Hartinger:29.5.2013 12:32

Teď koukám, že ho tam můžeš normálně použít, pokud chceš dělat jednu úlohu na pozadí, tak se s nějkými asynchronními metodami vůbec nezatěžuj, existují wrappery, co tě od toho odstíní.

Nahoru Odpovědět
29.5.2013 12:32
New kid back on the block with a R.I.P
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na David Hartinger
Petr Nymsa:29.5.2013 13:33

To je ten problém. UI prostě zamrzne. A aplikaci potom neuznají. Nevím, v téhle metodě je někde chybě.

Nyní jsem našel zpsůbo jak jednodušše načíst pixely -> byte array.

S tvorbou async metod přes await jsem neměl nikdy problém. V pohodě jsem měl metodu která generovala prvočísla do vysoké hodnoty, přes await a UI nezamrzlo.

Ještě se ozvu jak jsem to vyřešil, nyní už možná mám řešení.

Nahoru Odpovědět
29.5.2013 13:33
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Michal Žůrek - misaz:29.5.2013 14:29

Problém bude v té cizí knihovně.

 
Nahoru Odpovědět
29.5.2013 14:29
Avatar

Člen
Avatar
:29.5.2013 14:44

vim ze v tomto pripade je to blbe, ale myslim ze by to slo pres

Task.Run(()=> {
    //...
});
 
Nahoru Odpovědět
29.5.2013 14:44
Avatar
Odpovídá na
Michal Žůrek - misaz:29.5.2013 15:00

Vítej ve světě windows 8. Možná by to šlo a lidi z microsoftu používají (a na konferencích učí) Async a Await. Asi to nedělají ze srandy králikům. :)

 
Nahoru Odpovědět
29.5.2013 15:00
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na
Petr Nymsa:29.5.2013 15:00

Posílám update kód. Opavdu už nevím co a jak ;(. Pro update UI se musí využít Dispatcher. Je divné jedno - když ho nevolám a neupdatuju UI! UI zamrzne. Když ho Updatuju UI nezamrzá.

Metodu, která generuje volám takto

await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                     {
                          manager.GenerateAsciiHtml(bmp, pixels);
                     });

Metoda která generuje. GetPixel už je moje metoda.

public void GenerateAsciiHtml(BitmapImage bmp, byte[] pixels)
       {
           ascii = new StringBuilder();
           ascii.Append(string.Format("<body style=\"font-family: 'Courier New', Courier, monospace;font-size: {0}px;\">", 5));
           for (int h = 0; h < bmp.PixelHeight - Size; h += Size)
           {
               for (int w = 0; w < bmp.PixelWidth - Size; w += Size)
               {
                   Color color = bmp.GetPixel(pixels, w, h);
                   ascii.Append(string.Format("<span style='color:rgb({0},{1},{2});'>{3}{3}</span>",
                      color.R,color.G,color.B, getAsciiChar(color.A)));

               }
               ascii.Append("<br>");
           }
           ascii.Append("</body>");
       }

Metoda naschvál nic nevrací. V tomto případě UI nemrzne. Teď ovšem potřebuju jedno. Buď metoda nastaví text pro výpis přímo v sobě nebo vrátí string. Nastíním durhou situaci. Volání metody změním na

string text = "";
                    await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                        {
                            text =  manager.GenerateAsciiHtml(bmp, pixels);

                        });

do stringu text se přiřadí vrácený vygenerovaný HTML. Ovšem potřebuju udělat jedno. Binduju properties z manageru, tedy ze stejné třídy která generuje a má položku HTML. Jakimle se pokusím text přiřadit do HTML, UI zamrzne.

Dispatcher má v sobě metodu AsAsync() a ta má v sobě ContinueWith(), což by se mělo zavolat až po dokončení.

Mám v tom huláš a už nevím co a jak. Když udělám async i metodu ne generování dostávám error o tom že zasahuju do jiného vlákna.

Prosím nějaká rada, prostě kudy co a jak ? Děkuji moc ! :)

Nahoru Odpovědět
29.5.2013 15:00
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na
Petr Nymsa:29.5.2013 15:03

Ano to jsem zkoušel ale tohle mi prostě nefunguje. Zkoušel jsem i generovat číslo, vypočítavat z nich násobky + odmocniny a UI nezamrzlo. Asi je problém že mám tu metodu na generování a zároveň properties pro UI v jedné třídě.

http://vimeo.com/57608362 Zde podle nich i něco zkouším. Už fakt nevím jak :D.

KDyž načítám soubor, napíšu await a vše funguje. Ale tohle mi nestačí, nevím jak to funguje přesně pod pokličkou :/

Nahoru Odpovědět
29.5.2013 15:03
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar

Člen
Avatar
Odpovídá na Petr Nymsa
:29.5.2013 16:57

to si nemyslim, ze to je tou jednou tridou. A funguje to kdyz pocitas ty cisla a pak neco vratis?

Editováno 29.5.2013 16:58
 
Nahoru Odpovědět
29.5.2013 16:57
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na
Petr Nymsa:29.5.2013 17:11

Ano, počítám a vracím double. Schvále jsem měl i tu samotnou metodu async a každé nově vypočtené jsem připsal do souboru opět přes await (jinak to nejde). Vše fungovalo, UI nezamrzlo

Nahoru Odpovědět
29.5.2013 17:11
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Petr Nymsa
Tvůrce
Avatar
Petr Nymsa:29.5.2013 18:14

Asi už musím vypadat jako totální blbec. ale já opravdu už nevím jak ;( Už jsem ve stavu kdy bych to nejradši všechno vyhodil oknem :D.

Shrnu co tedy potřebuju a co mám.

Třída DataManager: Drží v sobě data pro Binding, je to čistě Model. Dříve jsem tam měl i metodu pro vygenerování HTML ASCII z obrázku. Přesunul jsem ji.

Třída PhotoAsciiWorker: Obsahuje metodu pro vygenerování HTML ASCII.

Ze třídy MainPage.xaml.cs -> třída která má přístup k View, zavolám metodu GenerateAScii z PhotoASciiWorker. Metoda by měla být asynchronně. Tedy aby UI nezamrzlo a napsalo třeba Working...

Co a jak nastavit ?

Do teď mi vždy stačilo označit metodu async a zavolat ji přes Await. Napíšu "možný" způsob zpracování

textBlock.Text = "Generating...Please wait";

Task<string> task = worker.GenerateAscii(.....) ;
string result = await task;

textBlock.Text = result;
 // ---> UI zamrzne
 // nebo
string reesult = await worker.GenerateAscii(...)

// UI zamrzne

Už fakt nevím co dělat :(

Nahoru Odpovědět
29.5.2013 18:14
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Odpovídá na Petr Nymsa
Michael Olšavský:29.5.2013 18:15

Nechceš se na to vykašlat a použít nové vlákno? :-)

 
Nahoru Odpovědět
29.5.2013 18:15
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na Michael Olšavský
Petr Nymsa:29.5.2013 18:20

A jak ? :D S vlákny moc kamarád nejsem. Tohle je navíc nové vlákno, je to akorát nový způsob http://msdn.microsoft.com/…h191443.aspx#… . Chápu jak to funguje ale nechápu proč to nefunguje v tomhle případě. Přitom když si udělám metodu která generuje náodná čísl,a násobí a dělá odmocninu + zapisuje furt do txt, UI nezamrzne

Nahoru Odpovědět
29.5.2013 18:20
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Petr Nymsa
Tvůrce
Avatar
Petr Nymsa:29.5.2013 18:29

Tak nyní zkouším už všechno možný. Nevím, prostě nevím. Zde třída PhotoAsciiWorker. Schválně jsem dal nastavení hodnot pro výpočet do jiné metody.

class PhotoAsciiWorker
    {
        byte[] pixels;
        BitmapImage bmp;
        int size;

        public void SetValues(BitmapImage bmp, byte[] pixels, int size)
        {
            this.pixels = pixels;
            this.bmp = bmp;
            this.size = size;
        }

        public string GenerateAsciiHtml()
        {
            StringBuilder ascii = new StringBuilder();
            ascii = new StringBuilder();
            ascii.Append(string.Format("<body style=\"font-family: 'Courier New', Courier, monospace;font-size: {0}px;\">", 5));



            for (int h = 0; h < bmp.PixelHeight - size; h += size)
            {
                for (int w = 0; w < bmp.PixelWidth - size; w += size)
                {
                    Color color = bmp.GetPixel(pixels, w, h);
                    ascii.Append(string.Format("<span style='color:rgb({0},{1},{2});'>{3}{3}</span>",
                       color.R, color.G, color.B, getAsciiChar(color.A)));

                }
                ascii.Append("<br>");
            }
            ascii.Append("</body>");


            return ascii.ToString();
        }

Zde volání metody

manager.HTML = "Working...";
                    worker.SetValues(bmp, pixels, manager.Size);
                    Task<string> task = Task.Run(new Func<string>(worker.GenerateAsciiHtml));

                    string result = await task;

                    manager.HTML = result;

Dostunu tento error:

The application called an interface that was marshalled for a different thread.
Nahoru Odpovědět
29.5.2013 18:29
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Odpovídá na Petr Nymsa
Michal Žůrek - misaz:29.5.2013 18:31

A nemělo by být GenerateAsciiHtml async?

 
Nahoru Odpovědět
29.5.2013 18:31
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na Michal Žůrek - misaz
Petr Nymsa:29.5.2013 18:33

Nn, zde ukázka testovacího progámku.

Task<double> task = Task.Run(new Func<double>(Calculate));
           double result = await task;
           txResult.Text = result.ToString();


 public double Calculate()
       {
           double r = 0;

           for (int i = 0; i < 10000 * 500 *200; i++)
           {
               r += Math.Sqrt(i);

               double bl = r * r * r * - Math.Pow(i,2) + Math.Sqrt(r);

           }

           return r;
       }

Vše funguje. UI nezamrzne

Editováno 29.5.2013 18:34
Nahoru Odpovědět
29.5.2013 18:33
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Odpovídá na Petr Nymsa
Michal Žůrek - misaz:29.5.2013 18:43

Tak tak udělej i ty pixely, pokud funguje o, tak musi i pixely.

 
Nahoru Odpovědět
29.5.2013 18:43
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na Michal Žůrek - misaz
Petr Nymsa:29.5.2013 18:45

To je to, nefunguje a já už absolutně nemám tušení proš o_O nebo jak mám prostrčit skrz Func i parametry metody které potřebuje ?

Nahoru Odpovědět
29.5.2013 18:45
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Petr Nymsa
Tvůrce
Avatar
Petr Nymsa:29.5.2013 21:06

Už toho mám akorát dost. Misaz mi poslal video kde ukázali jak dělat složité operace v jiném Threadu než je Thread UI -> UI nezamrzne. Kód může vypadat takto.

  private async void btnAsync_Click(object sender, RoutedEventArgs e)
        {
             // vytvoří nové vlákno, čeká na jeho dokončení. "Vyskočím" z //metody pryč. UI je aktivní dál
            long vysledek = await Task.Run<long>(() => Calculate(1000000000000));
 /// dokončilo se vlákno, pokračuju dál
            this.txResult.Text = vysledek.ToString();
}
  public long Calculate(long n)
        {
            long r = 0;

            for (long i = 0; i < n; i++)
                r += i;

            return r;
        }

Vše funguje jak má. Počítač počítá jak divý ale UI nezamrzlo. Nyní můj výpočet.

bmp = BitmapaNačtená ze souboru. Pixels = byte[] pixelů, size -> poměr pixel / char

manager.HTML = "Working...";
                    string result = await Task<string>.Run(() => worker.GenerateAsciiHtml(bmp, pixels, manager.Size));

                    manager.HTML = result;

Zde je metoda v jiné třídě.

public string GenerateAsciiHtml(BitmapImage bmp, byte[] pixels, int size)
        {
            StringBuilder ascii = new StringBuilder();
            ascii = new StringBuilder();
            ascii.Append(string.Format("<body style=\"font-family: 'Courier New', Courier, monospace;font-size: {0}px;\">", 5));



            for (int h = 0; h < bmp.PixelHeight - size; h += size)
            {
                for (int w = 0; w < bmp.PixelWidth - size; w += size)
                {
                    Color color = bmp.GetPixel(pixels, w, h);
                    ascii.Append(string.Format("<span style='color:rgb({0},{1},{2});'>{3}{3}</span>",
                       color.R, color.G, color.B, getAsciiChar(color.A)));

                }
                ascii.Append("<br>");
            }
            ascii.Append("</body>");


            return ascii.ToString();
        }

Skončí to chybou ihned v cyklu.

The application called an interface that was marshalled for a different thread.

Nevíte kde je problém ? Vím že asi otravuju ale já už fakt nevím :D

Nahoru Odpovědět
29.5.2013 21:06
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Odpovídá na Petr Nymsa
Michal Žůrek - misaz:29.5.2013 21:11

Já si pořád myslím že to dělá ta knihovna třetích stran...

 
Nahoru Odpovědět
29.5.2013 21:11
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na Michal Žůrek - misaz
Petr Nymsa:29.5.2013 21:12

Už tma žádnou nepoužívám. GetPixel je moje vlastní metoda. Všechno už je klasicky součástí WinRT

Nahoru Odpovědět
29.5.2013 21:12
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Odpovídá na Petr Nymsa
Michal Žůrek - misaz:29.5.2013 21:13

Tak se na to vys*r. :D

 
Nahoru Odpovědět
29.5.2013 21:13
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na Michal Žůrek - misaz
Petr Nymsa:29.5.2013 21:23

Nechci :D ... btw zjistil jsem následující. Že to volám z jiné třídy nevadí. Problém je v tom předávání Bitmapy. TU si načtu ze souboru / vyfotím kamerou a načítám / fotím ve stejné třídě jako volám tu metodu na generování. Poté to vlastně padá kvůli tomu že se snažím asi přistoupit k něčemu co je z jiného vlákna. Jak to vyřešit, nevíš ? :)

Nahoru Odpovědět
29.5.2013 21:23
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Petr Nymsa
Tvůrce
Avatar
Odpovídá na Michal Žůrek - misaz
Petr Nymsa:29.5.2013 21:35

Tak zde radí toto http://stackoverflow.com/…ent-thread-i a zde to samý http://social.msdn.microsoft.com/…ca081921f79/ ale to zase zamrzne UI.

Už ale vím kde je problém. Ten error vyskočí vždy když se snažím editovat něco z UI Thread, teď to Image. Neívm jak udělat to aby nezmarzlo UI ale zároveň dostal tu Bitmapu ....

Nahoru Odpovědět
29.5.2013 21:35
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
David Dostal
Tvůrce
Avatar
David Dostal:29.5.2013 23:46

Možná zde existuje něco jako Invoke u vláken. Ale nevím.

 
Nahoru Odpovědět
29.5.2013 23:46
Avatar

Člen
Avatar
Odpovídá na Petr Nymsa
:30.5.2013 7:02

A neslo by to, kdyby se ta bitmapa nejak naklonovala? Existuje metoda MemberwiseClone(), ale nevim co presne dela :)

 
Nahoru Odpovědět
30.5.2013 7:02
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 28 zpráv z 28.