Librería de códigos C# (Compartan aquí sus códigos)

<< < (4/5) > >>

Eleкtro:
Escanear un archivo o una url en VirusTotal.com

Se me ocurrió implementar la API 2.0 de VirusTotal en VB.NET, pero primero busqué para asegurarme de que nadie lo habia hecho todavía (de lo conrario sería absurdo reinventar la rueda), y descubrí que efectivamente ya alguien lo hizo, en C#. Os dejo el repositorio por aquí:

https://github.com/Genbox/VirusTotal.Net
PD: no lo he probado.

Saludos.

z3nth10n:
Thread Safe Bool: Implementación Thread-Safe de bools

El otro día me pasaba que al asignar una variable que estaba declarada en ambito de la clase desde otro thread, al leerla desde otro thread no me devolvía el resultado esperado, por eso os traigo esta utilidad.

Código
using System.Threading;
 
namespace GTAMapper.Extensions.Threading
{
   /// <summary>
   /// Thread safe enter once into a code block:
   /// the first call to CheckAndSetFirstCall returns always true,
   /// all subsequent call return false.
   /// </summary>
   public class ThreadSafeBool
   {
       private static int NOTCALLED = 0,
                          CALLED = 1;
 
       private int _state = NOTCALLED;
 
       /// <summary>Explicit call to check and set if this is the first call</summary>
       public bool Value
       {
           get
           {
               return Interlocked.Exchange(ref _state, CALLED) == NOTCALLED;
           }
       }
 
       /// <summary>usually init by false</summary>
       public static implicit operator ThreadSafeBool(bool called)
       {
           return new ThreadSafeBool() { _state = called ? CALLED : NOTCALLED };
       }
 
       public static implicit operator bool(ThreadSafeBool cast)
       {
           if (cast == null)
               return false;
 
           return cast.Value;
       }
   }
}

Extraído de: https://www.codeproject.com/Tips/375559/Implement-Thread-Safe-One-shot-Bool-Flag-with-Inte

z3nth10n:
ConcurrentQueuedCoroutines: Implementación Thread-Safe de ConcurrentQueues dentro de Coroutinas

La idea de esta utilidad es que cuando tu almacenas items desde otro thread, puedas acceder desde el thread principal.

Mezclando esta idea, con coroutinas, que básicamente, es un sistema del prehistorico que implementó Unity en su momento, que funciona de la siguiente forma, se crea un IEnumerator (con yields), el cual cada MoveNext se ejecuta en cada frame (yield return null) o cuando el programador especifique (yield return new WaitForSeconds(3) equivalente a Thread.Sleep(3000)) (por tal de no atorar el Main Thread, sí, Unity se ejecuta en un solo hilo).

Entonces, teniendo estas 2 cosas, porque no hacer Dequeue en cada MoveNext?

Código
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using UnityEngine;
 
namespace GTAMapper.Extensions.Threading
{
   public class ConcurrentQueuedCoroutines<T>
   {
       private List<Coroutine> coroutines;
       private Coroutine coroutine;
       private MonoBehaviour Mono;
 
       public ConcurrentQueue<object> Queue { get; private set; }
 
       public Action<T> Action { get; private set; }
       public bool Debugging { get; set; }
       public float SecondsToWait { get; private set; }
 
       private ConcurrentQueuedCoroutines()
       {
       }
 
       public ConcurrentQueuedCoroutines(float secondsToWait = -1)
       {
           Queue = new ConcurrentQueue<object>();
           coroutines = new List<Coroutine>();
           SecondsToWait = secondsToWait;
       }
 
       public Coroutine StartCoroutine(MonoBehaviour monoBehaviour, Action<T> action)
       {
           coroutines.Add(monoBehaviour.StartCoroutine(InternalCoroutine()));
           Mono = monoBehaviour;
           Action = action;
 
           return coroutine;
       }
 
       public Coroutine StartCoroutineOnce(MonoBehaviour monoBehaviour, Action<T> action)
       {
           if (Debugging)
               Debug.Log("Starting dequeing!");
 
           if (coroutine == null)
           {
               coroutine = monoBehaviour.StartCoroutine(InternalCoroutine());
               Mono = monoBehaviour;
               Action = action;
           }
 
           return coroutine;
       }
 
       public void StopCoroutine()
       {
           if (coroutine != null && Mono != null)
               Mono.StopCoroutine(coroutine);
       }
 
       public void StopAllCoroutines()
       {
           if (Mono != null && coroutines != null && coroutines.Count > 0)
               coroutines.ForEach((c) => Mono.StopCoroutine(c));
       }
 
       public IEnumerator GetCoroutine(MonoBehaviour mono, Action<T> action)
       {
           Mono = mono;
           Action = action;
           return InternalCoroutine();
       }
 
       private IEnumerator InternalCoroutine()
       {
           if (Debugging)
               Debug.Log($"Starting dequeing {Queue.Count} values!");
 
           while (Queue.Count > 0)
           {
               object value = null;
               bool dequeued = Queue.TryDequeue(out value);
 
               if (!dequeued)
               {
                   if (SecondsToWait == -1)
                       yield return new WaitForEndOfFrame();
                   else
                       yield return new WaitForSeconds(SecondsToWait);
 
                   continue;
               }
 
               Action?.Invoke((T)value);
 
               if (SecondsToWait == -1)
                   yield return new WaitForEndOfFrame();
               else
                   yield return new WaitForSeconds(SecondsToWait);
           }
       }
   }
}

Y diréis, y para que sirve esta chorra, pues por ejemplo, lo que se puede conseguir, es visualizar como se recorre una textura.





En el próximo post o enseñaré un caso de uso.

z3nth10n:
BatchedCoroutines: Iterar coroutinas una a una

Queréis que vuestras ConcurrentQueues se ejecuten una por una? No problemo, con esta implementación to hard-codeada lo conseguiréis:

Código
using GTAMapper.Extensions.Threading;
using System;
using System.Collections;
using UnityEngine;
 
namespace GTAMapper.Extensions
{
   public static class BatchedCoroutines
   {
       public static IEnumerator BatchCoroutines(
           MonoBehaviour monoBehaviour,
           Action finish,
           Func<int, bool>[] waitUntil = null,
           params Tuple<Action<object>, ConcurrentQueuedCoroutines<object>>[] tuple) // Tuple<Action<T>, ConcurrentQueuedCoroutines<T>> || dynamic
                                                                                     // Fix for: https://stackoverflow.com/questions/15417174/using-the-params-keyword-for-generic-parameters-in-c-sharp
       {
           int i = 0;
 
           foreach (var val in tuple)
           {
               if (waitUntil != null && waitUntil[i] != null)
                   yield return new WaitUntil(() => waitUntil[i](i));
 
               yield return val.Item2.GetCoroutine(monoBehaviour, val.Item1);
 
               ++i;
           }
 
           finish?.Invoke();
       }
   }
}

Un ejemplo de implementación:

Código
       protected ConcurrentQueuedCoroutines<object> debuggingCoroutine = new ConcurrentQueuedCoroutines<object>(),
                                                    colorCoroutine = new ConcurrentQueuedCoroutines<object>();
 
namespace GTAMapper.Core {
   public class Program : MonoBehaviour {
       public void Start() {
       StartCoroutine(BatchedCoroutines.BatchCoroutines(
               this,
               () => areCoroutinesCollected = true,
               F.GetFuncs(null, (_ii) => debuggingCoroutine.Queue.Count > 0),
               new Tuple<Action<object>, ConcurrentQueuedCoroutines<object>>((obj) =>
               {
                   Tuple<int, Color> tuple = (Tuple<int, Color>)obj;
 
                   int i = tuple.Item1,
                           _x = i % width,
                           _y = i / width;
 
                   UnityEngine.Color actualColor = debugTexture.GetPixel(_x, _y),
                                         mixedColor = UnityEngine.Color.Lerp(actualColor, tuple.Item2, .5f);
 
                   if (actualColor != mixedColor)
                   {
                       debugTexture.SetPixel(_x, _y, mixedColor);
                       debugTexture.Apply();
                   }
               }, colorCoroutine),
               new Tuple<Action<object>, ConcurrentQueuedCoroutines<object>>((obj) =>
               {
                   Color[] colors = (Color[])obj;
 
                   debugTexture.SetPixels32(colors.CastBack().ToArray());
                   debugTexture.Apply();
               }, debuggingCoroutine)));
         }
    }
}

Básicamente, en las dos Queues vamos haciendo Enqueue donde sea necesario (en otro thread).

Cuando todo haya acabado, desde el primer thread, llamamos a que se ejecute lo que acabo de mostrar.

Y en mi caso por ejemplo, esto sirve para mostrar pixel a pixel donde se ha iterado una imagen.

Y lo siguiente que ocurre es que la imagen se rellena con el algoritmo de flood-fill que enseñe el otro día. (Básicamente, para saber si se ha hecho bien)

Nota: Si queréis el código de GetFuncs es este:

Código
using System;
 
public static class F {
       public static Func<int, bool>[] GetFuncs(params Func<int, bool>[] waitUntil)
       {
           return waitUntil;
       }
}

z3nth10n:
Named Thread & Thread Marked: Pon nombres a tus threads

Código
using System;
using System.Collections.Generic;
using System.Threading;
 
namespace GTAMapper.Extensions.Threading
{
   public class ThreadMarker : IDisposable
   {
       //[ThreadStatic]
       //private static string __Name = $"Unity Thread #{Thread.CurrentThread.ManagedThreadId}";
 
       private static Dictionary<int, string> ThreadNames = new Dictionary<int, string>();
 
       public static string Name
       {
           get
           {
               lock (ThreadNames)
               {
                   try
                   {
                       return ThreadNames[Thread.CurrentThread.ManagedThreadId];
                   }
                   catch
                   {
                       return $"Unity Thread #{Thread.CurrentThread.ManagedThreadId}";
                   }
               }
           }
       }
 
       public ThreadMarker(string name)
       {
           lock (ThreadNames)
           {
               ThreadNames.AddOrSet(Thread.CurrentThread.ManagedThreadId, name);
           }
 
           // __Name = name;
       }
 
       public void Dispose()
       {
           ThreadNames.Remove(Thread.CurrentThread.ManagedThreadId);
           // __Name = "Un-Owned";
       }
   }
}

Código
using System;
 
namespace GTAMapper.Extensions.Threading
{
   public class NamedHandler<TArg>
   {
       public readonly Func<string, TArg> Handler;
 
       public NamedHandler(Func<string, TArg> handler)
       {
           Handler = arg =>
           {
               using (new ThreadMarker(arg))
               {
                   return handler(arg);
               }
           };
       }
   }
}

Caso de uso:

Código
int TaskId = new Random().Next();
 
ThreadPool.QueueUserWorkItem(new NamedHandler<WaitCallback>(name => new WaitCallback(BackgroundRunner)).Handler($"Ninja #{TaskId}"));

Navegación

[0] Índice de Mensajes

[#] Página Siguiente

[*] Página Anterior