Translate
martes, 24 de diciembre de 2019
Cuartos pasos en GIT
En Git, y otros sistemas de control de versiones distribuidos, clonar es la operación standard. Para obtener archivos se crea un clon de un repositorio entero. En otras palabras, prácticamente se crea una copia idéntica del servidor central. Todo lo que se pueda hacer en el repositorio principal, también podrás hacerlo.
Nosotros podemos inicializar un repositorio en un servidor central y luego clonarlo en nuestro equipo:
$ git clone otra.computadora:/ruta/a/archivos
y luego de clonarlo podemos hacer commit o pull :
$ git commit -a
$ git pull otra.computadora:/ruta/a/archivos HEAD
va a traer (pull) el estado de los archivos desde la otra máquina hacia la que estás trabajando. Si hiciste cambios que generen conflictos en un archivo, Git te va a avisar y deberías hacer commit luego de resolverlos.
Muchas veces deseamos hacer un fork de un proyecto, porque queremos probar una tecnología o porque queremos hacer cambios grandes, sin estorbar nuestro día a día por lo que podemos hacer un fork del proyecto y luego mergearlo cuando queramos, Entonces en tu servidor:
$ git clone git://servidor.principal/ruta/a/archivos
Y luego clonamos dicho fork en cada uno de los cliente, si terminamos el cambio de tecnología podemos mergear con el repositorio principal.
Empezando con Rust, parte 3
Seguimos con Rust...
Ahora implementaremos un clásico problema de programación : un juego de adivinanzas. Así es como va a funcionar: el programa generará un número entero aleatorio entre 1 y 100. Luego le pedirá al jugador que ingrese una suposición. Después de ingresar una suposición, el programa indicará si la suposición es demasiado baja o demasiado alta. Si la suposición es correcta, el juego imprimirá un mensaje de felicitación y saldrá.
Creemos un nuevo proyecto usando Cargo, así:
$ cargo new guessing_game
$ cd guessing_game
El primer comando, cargo new, toma el nombre del proyecto (guesssing_game) como primer argumento. El segundo comando cambia al directorio del nuevo proyecto.
Mire el archivo generado Cargo.toml:
[package]
name = "guessing_game"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
edition = "2018"
[dependencies]
Por supuesto cambiamos la info que viene por defecto.
cargo new genera un programa "¡Hola, mundo!" algo así:
fn main() {
println!("Hello, world!");
}
Ahora compilemos este programa "¡Hola, mundo!" Y ejecútelo en el mismo paso con el comando de ejecución de cargo:
$ cargo run
Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
Finished dev [unoptimized + debuginfo] target(s) in 1.50 secs
Running `target/debug/guessing_game`
Hello, world!
El comando de ejecución es útil cuando necesitamos ejecutar rápidamente en un proyecto.
Ya tenemos nuestro proyecto, ahora a seguir en otro post ...
Ahora implementaremos un clásico problema de programación : un juego de adivinanzas. Así es como va a funcionar: el programa generará un número entero aleatorio entre 1 y 100. Luego le pedirá al jugador que ingrese una suposición. Después de ingresar una suposición, el programa indicará si la suposición es demasiado baja o demasiado alta. Si la suposición es correcta, el juego imprimirá un mensaje de felicitación y saldrá.
Creemos un nuevo proyecto usando Cargo, así:
$ cargo new guessing_game
$ cd guessing_game
El primer comando, cargo new, toma el nombre del proyecto (guesssing_game) como primer argumento. El segundo comando cambia al directorio del nuevo proyecto.
Mire el archivo generado Cargo.toml:
[package]
name = "guessing_game"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
edition = "2018"
[dependencies]
Por supuesto cambiamos la info que viene por defecto.
cargo new genera un programa "¡Hola, mundo!" algo así:
fn main() {
println!("Hello, world!");
}
Ahora compilemos este programa "¡Hola, mundo!" Y ejecútelo en el mismo paso con el comando de ejecución de cargo:
$ cargo run
Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
Finished dev [unoptimized + debuginfo] target(s) in 1.50 secs
Running `target/debug/guessing_game`
Hello, world!
El comando de ejecución es útil cuando necesitamos ejecutar rápidamente en un proyecto.
Ya tenemos nuestro proyecto, ahora a seguir en otro post ...
domingo, 22 de diciembre de 2019
Terceros pasos en GIT.
Seguimos con GIT.
Cuando trabajamos de forma profesional debemos compartir nuestros cambios de forma tal de poder trabajar de forma colaborativa con nuestros compañeros, normalmente hacemos release cuando terminamos. Para hacer esto con Git, en el directorio donde guardamos nuestro código hacemos :
$ git init
$ git add .
$ git commit -m "Primer lanzamiento"
Entonces podemos decirle los otros desarrolladores que ejecuten:
$ git clone tu.maquina:/ruta/al/script
para descargar tu código. Esto asume que tienen acceso por ssh. Si no es así, podemos ejecutar git daemon y nuestros compañeros pueden usar:
$ git clone git://tu.maquina/ruta/al/script
De ahora en más, cada vez que necesitemos compartir código, escribimos :
$ git commit -a -m "Siguiente lanzamiento"
y los demás desarrolladores puede actualizar su versión yendo al directorio y ejecutando:
$ git pull
Averigua que cambios hiciste desde el último commit con:
$ git diff
O desde ayer:
$ git diff "@{yesterday}"
O entre una versión en particular y 2 versiones hacia atrás:
$ git diff SHA1_HASH "master~2"
En cada caso la salida es un patch (parche) que puede ser aplicado con git apply
Para ver cambios desde hace 2 semanas, se puede hacer:
$ git whatchanged --since="2 weeks ago"
Ojo ver esto se hace un tanto difícil, por lo que es una buena idea utilizar una software que nos deje ver los cambios de una forma más gráfica. Si te gusta la consola tig es una buena opción.
Cuando trabajamos de forma profesional debemos compartir nuestros cambios de forma tal de poder trabajar de forma colaborativa con nuestros compañeros, normalmente hacemos release cuando terminamos. Para hacer esto con Git, en el directorio donde guardamos nuestro código hacemos :
$ git init
$ git add .
$ git commit -m "Primer lanzamiento"
Entonces podemos decirle los otros desarrolladores que ejecuten:
$ git clone tu.maquina:/ruta/al/script
para descargar tu código. Esto asume que tienen acceso por ssh. Si no es así, podemos ejecutar git daemon y nuestros compañeros pueden usar:
$ git clone git://tu.maquina/ruta/al/script
De ahora en más, cada vez que necesitemos compartir código, escribimos :
$ git commit -a -m "Siguiente lanzamiento"
y los demás desarrolladores puede actualizar su versión yendo al directorio y ejecutando:
$ git pull
Averigua que cambios hiciste desde el último commit con:
$ git diff
O desde ayer:
$ git diff "@{yesterday}"
O entre una versión en particular y 2 versiones hacia atrás:
$ git diff SHA1_HASH "master~2"
En cada caso la salida es un patch (parche) que puede ser aplicado con git apply
Para ver cambios desde hace 2 semanas, se puede hacer:
$ git whatchanged --since="2 weeks ago"
Ojo ver esto se hace un tanto difícil, por lo que es una buena idea utilizar una software que nos deje ver los cambios de una forma más gráfica. Si te gusta la consola tig es una buena opción.
jueves, 19 de diciembre de 2019
Aprende los fundamentos de la inteligencia artificial para tu empresa
Microsoft nos regala un e-book el cual nos invita a leerlo de la siguiente manera:
Prepárate para unirte al 85 % de las empresas que se prevé que usarán inteligencia artificial (IA) en 2020.
Lee el e-book Conceptos básicos de IA para empresas para entender cómo aplicar la inteligencia artificial para generar nuevo valor comercial y reinventar tu organización. Comienza con algunos aspectos básicos, como una introducción a la inteligencia artificial e indicadores clave para implementar tus primeras tecnologías inteligentes. Los temas incluyen el uso de IA para:
- Transformar tus procesos empresariales.
- Interactuar con los clientes y empoderarlos.
- Optimizar tus operaciones.
Dejo link: https://info.microsoft.com/ww-landing-aI-basics-for-business-eBook.html?lcid=es-es&WT.mc_ID=NEWS_EPG_Spain_DICIEMBRE&wt.mc_id=AID2392225_EML_6224385
Libros de Java Code Geeks
martes, 17 de diciembre de 2019
Segundos pasos en GIT
Sigamos revisando algunos comandos de GIT. Si necesitamos ir a un commit anterior debemos saber su id, el id es un hash del commit, por lo tanto podemos listar todos los commit recientes con :
$ git log
Luego podemos ir hasta el commit determinado con :
$ git reset --hard SHA1_HASH
Ojo esto va a borrar a los commit más nuevos. Pero si queremos saltar a un estado anterior temporalmente usamos :
$ git checkout SHA1_HASH
Esto te lleva atrás en el tiempo, sin tocar los commits más nuevos. Sin embargo,
como en los viajes en el tiempo de las películas de ciencia ficción, estarás en una
realidad alternativa, porque tus acciones fueron diferentes a las de la primera
vez. Esta realidad alternativa se llama branch (rama). Por ahora solo recordemos que :
$ git checkout master
te llevará al presente. También, para que Git no se queje, siempre debemos hacer un commit o resetear los cambios antes de ejecutar checkout.
Puedes elegir commits específicos para deshacer.
$ git commit -a
$ git revert SHA1_HASH
va a deshacer solo el commit con el hash dado. Ejecutar git log revela que el
revert es registrado como un nuevo commit.
Hasta ahora solo hemos trabajado con nuestro repositorio local que es un poco raro, normalmente tambien tenemos un repositorio remoto donde poder compartir código con los demás desarrolladores. Si queremos obtener una copia de un repositorio remoto debemos clonar este repositorio:
$ git clone git://servidor/ruta/a/los/archivos
luego de clonarlo podemos obtener su última versión con pull :
$ git pull
$ git log
Luego podemos ir hasta el commit determinado con :
$ git reset --hard SHA1_HASH
Ojo esto va a borrar a los commit más nuevos. Pero si queremos saltar a un estado anterior temporalmente usamos :
$ git checkout SHA1_HASH
Esto te lleva atrás en el tiempo, sin tocar los commits más nuevos. Sin embargo,
como en los viajes en el tiempo de las películas de ciencia ficción, estarás en una
realidad alternativa, porque tus acciones fueron diferentes a las de la primera
vez. Esta realidad alternativa se llama branch (rama). Por ahora solo recordemos que :
$ git checkout master
te llevará al presente. También, para que Git no se queje, siempre debemos hacer un commit o resetear los cambios antes de ejecutar checkout.
Puedes elegir commits específicos para deshacer.
$ git commit -a
$ git revert SHA1_HASH
va a deshacer solo el commit con el hash dado. Ejecutar git log revela que el
revert es registrado como un nuevo commit.
Hasta ahora solo hemos trabajado con nuestro repositorio local que es un poco raro, normalmente tambien tenemos un repositorio remoto donde poder compartir código con los demás desarrolladores. Si queremos obtener una copia de un repositorio remoto debemos clonar este repositorio:
$ git clone git://servidor/ruta/a/los/archivos
luego de clonarlo podemos obtener su última versión con pull :
$ git pull
lunes, 16 de diciembre de 2019
Primeros pasos en GIT
Antes de empezar a leer, espero que estés familiarizado con conceptos como control de versiones, conflictos, merge, branch, etc… Porque no tengo ganas de explicarlos :(
Antes, cada proyecto usaba un control de versiones centralizado un ejemplo es SVN. Un servidor en algún lado contenía todo el código. Nadie más los tenía. Cada programador tenía una versión y una parte del código. Cada tanto debíamos actualizar del servidor central, obteníamos la última versión del servidor principal, programábamos un rato y volvía a subir al servidor para que todos los demás
pudieran usarlo.
Cual es el problema de este esquema? Que si 2 desarrolladores quieren comparar 2 soluciones para un mismo problema, no lo pueden hacer sin subir al repositorio central y eso esta mal porque no saben cual solución debe ser la mejor para ser compartida. GIT soluciona este problema utilizando un modelo distribuido, en el cual cada cliente tiene un repositorio y existe uno o varios repositorios remotos. De esta manera podemos subir nuestros cambios al repositorio local, comparar las soluciones y luego subirlas al repositorio compartido. A la vez el repositorio local contiene todo el historial del código, de esta manera es innecesario comunicación con el repositorio remoto para retornar a una versión antigua.
Al empezar con GIT podemos tomar un repositorio remoto o obtar por utilizar nuestro repositorio local. Veamos como podemos tener un proyecto y mantenerlo en el repositorio local:
Inicio el repositorio con init
$ git init
Agrego todos los archivos de esa carpeta
$ git add .
Hago commit es decir subo los archivos al repositorio
$ git commit -m "Mi primer commit"
Si deseamos volver a la version del repositorio:
$ git reset --hard
Si añades nuevos archivos o subdirectorios, deberás decirle a Git:
$ git add ARCHIVOSNUEVOS…
De manera similar, si quieres que Git se olvide de determinados archivos, porque (por ejemplo) los borraste:
$ git rm ARCHIVOSVIEJOS…
Renombrar un archivo es lo mismo que eliminar el nombre anterior y agregar el
nuevo. También puedes usar git mv que tiene la misma sintaxis que el comando
mv de linux. Por ejemplo:
$ git mv ARCHIVOVIEJO ARCHIVONUEVO
Y por este post estuvimos bien...
viernes, 13 de diciembre de 2019
Introducción a Jakarta NoSQL
EE4J no se detiene y ha aprobado el proyecto Jakarta NoSQL es una especificación en Jakarta EE para ayudar a los desarrolladores a crear aplicaciones de nivel empresarial utilizando tecnologías Java y NoSQL. JNoSQL es la implementación de referencia de Jakarta NoSQL, que proporciona un conjunto de APIs y una implementación estándar para una serie de bases de datos NoSQL, como Cassandra, MongoDB, Neo4J, CouchDB y OrientDB, entre otras.
Jakarta NoSQL consiste en una capa de comunicación (Diana), que extrae un conjunto de APIs diseñadas para definir la comunicación con las bases de datos NoSQL. Contiene cuatro módulos de acuerdo con cada tipo de base de datos NoSQL: clave-valor, familia de columnas, documento y grafo; y una capa de mapeo (Artemis), que proporciona una serie de APIs para ayudar a los desarrolladores a integrar aplicaciones Java con bases de datos NoSQL. La capa de mapeo se basa en anotaciones y utiliza tecnologías como CDI y Bean Validation, lo que facilita el uso de los desarrolladores. Es posible comparar la capa de mapeo con JPA / Hibernate en el mundo tradicional RDBMS.
La definición de una entidad es relativamente similar a JPA. Básicamente usa @Entity, @Id, @Column y así sucesivamente:
@Entity
public class Person {
@Id
private long id;
@Column
private String name;
@Column
private List phones;
}
Los repositorios se parecen a los repositorios de Spring Data, donde se extiende un Repositorio <T, ID>:
public interface PersonRepository extends Repository {
List<Person> findByName(String name);
Stream<Person> findByPhones(String phone);
}
Sin embargo, a partir de este momento, las cosas cambian, ya que las dependencias de Maven cambian de acuerdo con el tipo de base de datos NoSQL que se usa, así como la configuración y cómo inyectamos el repositorio en nuestros servicios.
Veamos 2 ejemplos, uno utilizando una base orientada a columna y otra documental. Importamos librerías :
<dependency>
<groupId>org.jnosql.artemis</groupId>
<artifactId>artemis-column</artifactId>
<version>0.0.9</version>
</dependency>
<dependency>
<groupId>org.jnosql.diana</groupId>
<artifactId>cassandra-driver</artifactId>
<version>0.0.9</version>
</dependency>
Veamos el manager de nuestra base orientada a columna :
@ApplicationScoped
public class ColumnFamilyManagerProducer {
private static final String KEY_SPACE = "developers";
private ColumnConfiguration<> cassandraConfiguration;
private ColumnFamilyManagerFactory managerFactory;
@PostConstruct
public void init() {
cassandraConfiguration = new CassandraConfiguration();
managerFactory = cassandraConfiguration.get();
}
@Produces
public ColumnFamilyManager getManagerCassandra() {
return managerFactory.get(KEY_SPACE);
}
}
Y finalmente, un ejemplo de cómo ejecutar algunas inserciones / consultas:
Person person = Person.builder()
.withPhones(Arrays.asList("234", "432"))
.withName("Name")
.withId(id)
.build();
//using ColumnTemplate
ColumnTemplate columnTemplate = container.select(CassandraTemplate.class).get();
Person saved = columnTemplate.insert(PERSON);
System.out.println("Person saved" + saved);
ColumnQuery query = select().from("Person").where(eq(Column.of("id", 1L))).build();
Optional<Person> person = columnTemplate.singleResult(query);
System.out.println("Entity found: " + person);
//using PersonRepository
PersonRepository repository = container.select(PersonRepository.class).select(ofColumn()).get();
Person saved = repository.save(PERSON);
System.out.println("Person saved" + saved);
Optional<Person> person = repository.findById(1L);
System.out.println("Entity found: " + person);
Veamos un ejemplo con una base documental, primero las dependencias:
<dependency>
<groupId>org.jnosql.artemis</groupId>
<artifactId>artemis-document</artifactId>
<version>0.0.9</version>
</dependency>
<dependency>
<groupId>org.jnosql.diana</groupId>
<artifactId>mongodb-driver</artifactId>
<version>0.0.9</version>
</dependency>
Luego el manager :
@ApplicationScoped
public class DocumentCollectionManagerProducer {
private static final String COLLECTION = "developers";
private DocumentConfiguration configuration;
private DocumentCollectionManagerFactory managerFactory;
@PostConstruct
public void init() {
configuration = new MongoDBDocumentConfiguration();
Map<String, Object> settings = Collections.singletonMap("mongodb-server-host-1", "localhost:27017");
managerFactory = configuration.get(Settings.of(settings));
}
@Produces
public DocumentCollectionManager getManager() {
return managerFactory.get(COLLECTION);
}
}
y usamos el manager :
Person person = Person.builder()
.withPhones(Arrays.asList("234", "432"))
.withName("Name")
.withId(id)
.build();
//using DocumentTemplate
DocumentTemplate documentTemplate = container.select(DocumentTemplate.class).get();
Person saved = documentTemplate.insert(person);
System.out.println("Person saved" + saved);
DocumentQuery query = select().from("Person")
.where(eq(Document.of("_id", id))).build();
Optional<Person> personOptional = documentTemplate.singleResult(query);
System.out.println("Entity found: " + personOptional);
//using PersonRepository
PersonRepository repository = container.select(PersonRepository.class)
.select(ofDocument()).get();
repository.save(person);
List<Person> people = repository.findByName("Name");
System.out.println("Entity found: " + people);
repository.findByPhones("234").forEach(System.out::println);
Y listo!
Ustedes pensaran que feo tener diferentes modos de guardar y recuperar datos de nuestros almacenes de datos sql pero tengamos en cuenta que es el único camino para aprovechar al máximo sus particularidades y normalmente elegimos estas bases por sus particularidades.
Dejo link: https://github.com/eclipse-ee4j/nosql
Un IDE online para programar en javascript
Tiene muchas funcionalidades, la que más me gusta es que si necesitas alguna librería podes importarla ahí mismo...
Sin más ...
Dejo link :
https://codesandbox.io/
lunes, 9 de diciembre de 2019
Seguimos con Docker
Creo que recuerdan los post anteriores...
El ciclo de vida de un contenedor esta detallado en dicha ilustración :
La vida de un contenedor comienza en el estado creado o created, esta creado pero no esta funcionando, por lo que el siguiente estado es running y pasa a este estado con el comando run, donde el contenedor comienza a funcionar. Desde este estado puede pasar a diferentes estados.
Killed es cuando matamos el contenedor, normalmente se utiliza cuando hay un problema o el contenedor no contesta y el contenedor pasa a killed
Paused, nuestro contenedor es pausado cuando estamos haciendo una tarea y no podemos continuar en ese momento pero luego queremos seguir. Es como hibernar la pc.
Stopped (con el comando stop) es cuando paramos la imagen, la apagamos y luego podemos volver a running con el comando run.
El ciclo de vida de un contenedor esta detallado en dicha ilustración :
La vida de un contenedor comienza en el estado creado o created, esta creado pero no esta funcionando, por lo que el siguiente estado es running y pasa a este estado con el comando run, donde el contenedor comienza a funcionar. Desde este estado puede pasar a diferentes estados.
Killed es cuando matamos el contenedor, normalmente se utiliza cuando hay un problema o el contenedor no contesta y el contenedor pasa a killed
Paused, nuestro contenedor es pausado cuando estamos haciendo una tarea y no podemos continuar en ese momento pero luego queremos seguir. Es como hibernar la pc.
Stopped (con el comando stop) es cuando paramos la imagen, la apagamos y luego podemos volver a running con el comando run.
Que es Python Global Interpreter Lock?
Antes de empezar necesitamos unos conceptos importantes. Dado que concurrencia y paralelismo son dos conceptos relacionados y mucha gente los confunde debemos empezar marcando las diferencias.
La concurrencia significa, esencialmente, que tanto la tarea A como la B deben suceder independientemente una de otra, y A comienza a ejecutarse, y luego B comienza antes de que A termine.
Hay varias formas diferentes de lograr la concurrencia. Uno de ellos es el paralelismo: tener varias CPU trabajando en las diferentes tareas al mismo tiempo. Pero esa no es la única manera. Otro es por cambio de tareas, que funciona así: la tarea A funciona hasta cierto punto, luego la CPU que trabaja en ella se detiene y cambia a la tarea B, trabaja en ella por un tiempo y luego vuelve a la tarea A. Si los intervalos de tiempo son lo suficientemente pequeños, puede parecerle al usuario que ambas cosas se ejecutan en paralelo, a pesar de que en realidad están siendo procesadas en serie por una CPU multitarea. Se entendió? es como que concurrencia es la sensación de paralelismo, pero no necesariamente es paralelismo. En cambio paralelismo es hacer cosas en paralelo posta.
Y dada esta aclaración, hablemos de GIL, es el mecanismo utilizado en CPython para impedir que múltiples threads modifiquen los objetos de Python a la vez en una aplicación multi hilo. Esto no evita que tengamos que utilizar primitivas de sincronización en nuestras aplicaciones en Python.
Si en nuestras aplicaciones tenemos varios threads accediendo a una sección de código con datos mutables, tendremos un problema si no utilizamos primitivas de sincronización. Veamos un ejemplo de thread :
from threading import Thread
def una_funcion:
print “¡Hola Mundo!”
thread1 = Thread(target=una_funcion)
thread1.start()
thread1.join()
Se puede notar que importamos la clase Thread del módulo threading e instanciamos un nuevo objeto de tipo Thread al que le pasamos la funcion una_funcion. Lo ejecutamos y bloqueamos el hilo de ejecución principal del script hasta que el thread1 regrese de la sección crítica.
Al igual que en otros lenguajes, si queremos que solo un hilo de ejecución haga cambios en los datos de la sección crítica, debemos hacer uso de la clase Lock que nos permite adquirir una sección crítica.
El GIL es un bloqueo a nivel de intérprete. Este bloqueo previene la ejecución de múltiples hilos a la vez en un mismo intérprete de Python. Cada hilo debe esperar a que el GIL sea liberado por otro hilo.
Aunque CPython utiliza el soporte nativo del sistema operativo donde se ejecute a la hora de manejar hilos, y la implementación nativa del sistema operativo permite la ejecución de múltiples hilos de forma simultánea, el intérprete CPython fuerza a los hilos a adquirir el GIL antes de permitirles acceder al intérprete, la pila y puedan así modificar los objetos Python en memoria.
En definitiva, el GIL protege la memoria del intérprete que ejecuta nuestras aplicaciones y no a las aplicaciones en sí. El GIL también mantiene el recolector de basura en un correcto y saneado funcionamiento.
El recolector de basura de Python, como todos los recolectores de basura de diferentes lenguajes de programación, se encarga de liberar la memoria cuando terminamos de usar un objeto. En Python, este mecanismo hace uso de un concepto denominado conteo de referencias.
Cada vez que se hace referencia a un objeto instanciado (un int, una cadena o cualquier otro tipo de objeto nativo o propio) el recolector de basura lo monitorea y suma uno al contador de referencias al objeto. Cuando este número llega al cero, significa que el objeto no está más en uso y el recolector de basura procede a su eliminación de la memoria.
De esta forma no debemos preocuparnos nosotros mismos por liberar la memoria y limpiar los objetos que van a dejar de ser usados como si tenemos que hacer por ejemplo en C o C++. El GIL impide que un thread decremente el valor del conteo de referencia de un objeto a cero mientras otro thread está haciendo uso del mismo. Solo un thread puede acceder a un objeto Python a la vez.
El GIL permite que la implementación de CPython sea extremadamente sencilla a la vez que incrementa la velocidad de ejecución de aplicaciones con un único hilo y la ejecución de aplicaciones multi hilo en sistemas que cuentan con un único procesador. Facilita el mantenimiento del intérprete así como la escritura de módulos y extensiones para el mismo.
Esto es genial, pero también impide la ejecución de múltiples hilos de procesamiento en paralelo en sistemas con múltiples procesadores.
El GIL no es tan malo como puede aparentar a primera vista. Los módulos que realizan tareas de computación intensiva como la compresión o la codificación liberan el GIL mientras operan. También es liberado en todas las operaciones de E/S.
Lo cierto es que si. En 1999 Greg Stein, director de la Apache Software Foundation, y mantenedor de Python y sus librerías desde 1999 al 2003, creó un parche para el intérprete que eliminaba completamente el GIL y añadía bloqueo granular alrededor de operaciones sensibles en el intérprete.
Este parche incrementaba la velocidad de ejecución de aplicaciones multi-hilo pero la decrementaba a la mitad en aplicaciones que ejecutaban un único hilo, lo cual, no era aceptable. Por supuesto esa rama de desarrollo de CPython no tiene ningún tipo de mantenimiento y es hoy inaccesible :(
Por ende con GIL solo tenemos concurrencia y no paralelismo...
Seguimos con Docker
Creo que recuerdan los post anteriores...
Docker trae muchas herramientas para trabajar de forma eficiente con contenedores.
Un comando muy usado es docker top, que un usuario de linux o unix le hace pensar en el comando top, el cual muestra los procesos y los recursos que consumen se forma interactiva.
En docker a este comando se le pasa el id del contenedor, de la siguiente manera :
docker top ContainerID
De esta manera podemos saber información de contenedor.
Con docker stop podemos parar una contenedor que esta corriendo:
docker stop ContainerID
Con rm borramos un contenedor:
docker rm ContainerID
Con docker stats, podemos saber estadísticas de nuestro contenedor :
docker stats ContainerID
Con pause, pausamos un contenedor, lo que significa que docker va a pausar todos los proceso del contenedor, para luego poder volverlos a iniciar con unpause :
docker pause ContainerID
docker unpause ContainerID
Con kill matamos el contenedor, sirve para matar el proceso cuando tenemos un problema o no responde :
docker kill ContainerID
jueves, 5 de diciembre de 2019
Libros Gratuitos de Java geeks
Quiero compartir estos libros de java geeks:
|
lunes, 2 de diciembre de 2019
Seguimos con Docker
Seguimos con Docker...
Nosotros podemos correr un ubuntu con el siguiente comando :
Docker run –it Ubuntu bash
Docker hub es el lugar donde se pueden registrar imagenes de docker, las cuales se pueden bajar posteriormente.
https://www.docker.com/products/docker-hub
En esta pagina podemos buscar una imagen que necesitamos, y luego con el comando pull podemos descargar esta imagen para luego poder correrla. Veamos un ejemplo con una imagen de jenskins :
sudo docker pull jenkins
sudo docker run -p 8080:8080 -p 50000:50000 jenkins
con la opción -p estamos indicando que publique un puerto determinado indicando el puerto origen y el destino separado por dos puntos “:”
Docker se basa en imagenes, todas son imagenes que podemos bajar y correr, por ejemplo con :
sudo docker run centos –it /bin/bash
Estamos corriendo una imagen llamada centos y lo hace de forma interactiva, y cuando levante va a utilizar el bash de este sistema.
Si deseamos saber que imágenes tenemos debemos hacer :
docker images
Cuando ejecutamos este comando obtendremos:
La imagen puede bajarse utilizando el comando run y el nombre de la imagen. Con este comando bajamos la imagen y la corremos.
Nosotros podemos remover las imágenes con docker rmi , pasandole el id de la imagen, por ejemplo :
docker rmi ImageID
Los contenedores son instancias de imágenes Docker que se pueden ejecutar con el comando Docker run. El propósito básico de Docker es ejecutar contenedores.
La ejecución de contenedores se gestiona con el comando Docker run. Para ejecutar un contenedor en modo interactivo, primero inicie el contenedor Docker.
sudo docker run –it centos /bin/bash
Uno puede enumerar todos los contenedores a través del comando docker ps. Este comando se utiliza para devolver los contenedores actualmente en ejecución.
docker ps -a se utiliza para enumerar todos los contenedores en el sistema.
Y creo que por ahora estamos bien!!
Nosotros podemos correr un ubuntu con el siguiente comando :
Docker run –it Ubuntu bash
Docker hub es el lugar donde se pueden registrar imagenes de docker, las cuales se pueden bajar posteriormente.
https://www.docker.com/products/docker-hub
En esta pagina podemos buscar una imagen que necesitamos, y luego con el comando pull podemos descargar esta imagen para luego poder correrla. Veamos un ejemplo con una imagen de jenskins :
sudo docker pull jenkins
sudo docker run -p 8080:8080 -p 50000:50000 jenkins
con la opción -p estamos indicando que publique un puerto determinado indicando el puerto origen y el destino separado por dos puntos “:”
Docker se basa en imagenes, todas son imagenes que podemos bajar y correr, por ejemplo con :
sudo docker run centos –it /bin/bash
Estamos corriendo una imagen llamada centos y lo hace de forma interactiva, y cuando levante va a utilizar el bash de este sistema.
Si deseamos saber que imágenes tenemos debemos hacer :
docker images
Cuando ejecutamos este comando obtendremos:
- El Tag o nombre de la imagen,
- El Id de la imagen que es un dato externo.
- La fecha de creación
- y la cantidad de byte que ocupa la imagen.
La imagen puede bajarse utilizando el comando run y el nombre de la imagen. Con este comando bajamos la imagen y la corremos.
Nosotros podemos remover las imágenes con docker rmi , pasandole el id de la imagen, por ejemplo :
docker rmi ImageID
Los contenedores son instancias de imágenes Docker que se pueden ejecutar con el comando Docker run. El propósito básico de Docker es ejecutar contenedores.
La ejecución de contenedores se gestiona con el comando Docker run. Para ejecutar un contenedor en modo interactivo, primero inicie el contenedor Docker.
sudo docker run –it centos /bin/bash
Uno puede enumerar todos los contenedores a través del comando docker ps. Este comando se utiliza para devolver los contenedores actualmente en ejecución.
docker ps -a se utiliza para enumerar todos los contenedores en el sistema.
Y creo que por ahora estamos bien!!
domingo, 1 de diciembre de 2019
Empezando con Rust, parte 2
Seguimos con Rust...
Cargo es el sistema de construcción y administrador de paquetes de Rust. La mayoría de los Rustaceanos usan esta herramienta para administrar sus proyectos de Rust porque Cargo maneja muchas tareas, como compilar el código, descargar dependencias y construir esas dependencias.
Los programas Rust más simples, como el que hemos escrito hasta ahora, no tienen dependencias. Entonces, si hubiéramos construido Hello, world! proyecto con Cargo, solo usaría la parte de Cargo que maneja la compilación. A medida que escriba programas Rust más complejos, agregará dependencias, y si comienza un proyecto con Cargo, será mucho más fácil agregar dependencias.
Cargo viene instalado con Rust podemos verificar si Cargo está instalado escribiendo lo siguiente en la terminal:
$ cargo --version
Si ve un número de versión, ¡lo tiene! Si ve un error, como “command not found”, consulte la documentación de su método de instalación para determinar cómo instalar Cargo por separado.
Creemos un nuevo proyecto con Cargo y veamos cómo se diferencia de nuestro Hello, world original. Vamos a la carpeta donde pondremos el código. Luego, ejecutamos lo siguiente:
$ cargo new hello_cargo
$ cd hello_cargo
El primer comando crea un nuevo directorio llamado hello_cargo. Hemos llamado a nuestro proyecto hello_cargo, y Cargo crea sus archivos en un directorio del mismo nombre.
Con "cd hello_cargo" nos hubicamos en el directorio hello_cargo y si ejecutamos ls podremos ver los archivos. Cargo ha generado dos archivos y un directorio: un archivo Cargo.toml y un directorio src con un archivo main.rs dentro. También ha inicializado un nuevo repositorio de Git junto con un archivo .gitignore.
Si abrimos Cargo.toml con un editor de texto. Debería verse algo así :
[package]
name = "hello_cargo"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
edition = "2018"
[dependencies]
Este archivo está en el formato TOML (Tom's Obvious, Minimal Language), que es el formato de configuración de Cargo.
La primera línea, [paquete], es un encabezado de sección que indica que las siguientes declaraciones están configurando un paquete. A medida que agreguemos más información a este archivo, agregaremos otras secciones.
Las siguientes cuatro líneas establecen la información de configuración que Cargo necesita para compilar su programa: el nombre, la versión, quién lo escribió y la edición de Rust para usar. Cargo obtiene su nombre e información de correo electrónico de su entorno, por lo que si esa información no es correcta, se puede correjir y guarde el archivo.
La última línea, [dependencias], es el comienzo de una sección de dependencias del proyecto. En Rust, los paquetes de código se denominan cajas. No necesitaremos ninguna otra caja para este proyecto, por lo que no usaremos esta sección de dependencias.
Ahora abra src / main.rs y veremos lo siguiente:
fn main() {
println!("Hello, world!");
}
Cargo ha generado un Hola, mundo! programa similar al post anterior. Hasta ahora, las diferencias entre nuestro proyecto anterior y el proyecto que genera Cargo son que Cargo colocó el código en el directorio src, y tenemos un archivo de configuración Cargo.toml en el directorio superior.
Cargo espera que sus archivos de origen vivan dentro del directorio src. El directorio de proyectos de nivel superior es solo para archivos README, información de licencia, archivos de configuración y cualquier otra cosa que no esté relacionada con su código. Usar Cargo te ayuda a organizar tus proyectos. Hay un lugar para todo, y todo está en su lugar.
Si comenzó un proyecto que no usa Cargo, como hicimos con Hello, world! proyecto, puede convertirlo en un proyecto que use Cargo. Lo que tenemos que hacer es mover el código del proyecto al directorio src y crear un archivo Cargo.toml apropiado.
Desde el directorio hello_cargo, compilaremos el proyecto ingresando el siguiente comando:
$ cargo build
Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 2.85 secs
Este comando crea un archivo ejecutable en target/debug/hello_cargo (o target \debug\hello_cargo.exe en Windows) y luego podemos ejecurar dicho programa.
$ ./target/debug/hello_cargo
Hello, world!
Si todo va bien, "Hello, world!" debe ser impreso en la terminal. La ejecución de la construcción por primera vez también hace que Cargo cree un nuevo archivo en el nivel superior: Cargo.lock. Este archivo realiza un seguimiento de las versiones exactas de las dependencias en su proyecto. Este proyecto no tiene dependencias, por lo que el archivo va a estar vacio. Nunca necesitará cambiar este archivo manualmente; Cargo gestiona sus contenidos.
Acabamos de construir un proyecto con Cargo Build y lo ejecutamos con ./target/debug/hello_cargo, pero también podemos usar "Cargo Run" para compilar el código y luego ejecutarlo :
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Running `target/debug/hello_cargo`
Hello, world!
Tenga en cuenta que esta vez no hemos visto resultados que indiquen que Cargo estaba compilando hello_cargo. Cargo descubrió que los archivos no habían cambiado, por lo que simplemente ejecutó el binario. Si hubiera modificado su código fuente, Cargo habría reconstruido el proyecto antes de ejecutarlo, y habría visto este resultado:
$ cargo run
Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 0.33 secs
Running `target/debug/hello_cargo`
Hello, world!
"cargo check" verifica rápidamente su código para asegurarse de que se compila pero no produce un ejecutable:
$ cargo check
Checking hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs
¿Por qué no querrías un ejecutable? A menudo, la verificación de Cargo es mucho más rápida que la compilación, ya que omite el paso de producir un ejecutable. Si continuamente revisas tu trabajo mientras escribes el código, ¡usar el control de carga acelerará el proceso! Como tal, muchos Rustaceanos realizan controles de Cargo periódicamente mientras escriben su programa para asegurarse de que se compila. Luego ejecutan la construcción de carga cuando están listos para usar el ejecutable.
Recapitulemos lo que hemos aprendido hasta ahora sobre Cargo:
- Podemos construir un proyecto utilizando "cargo build" o "cargo check".
- Podemos construir y ejecutar un proyecto en un solo paso utilizando "cargo run".
- En lugar de guardar el resultado de la compilación en el mismo directorio que nuestro código, Cargo lo almacena en el directorio de /target/debug.
Una ventaja adicional de usar Cargo es que los comandos son los mismos sin importar en qué sistema operativo esté trabajando.
Cuando su proyecto finalmente esté listo para su lanzamiento, puede usar la construcción Cargo de tipo release para compilarlo con optimizaciones. Este comando creará un ejecutable en target/release en lugar de target/debug. Las optimizaciones hacen que su código Rust se ejecute más rápido, pero activarlas alarga el tiempo que tarda su programa en compilarse. Es por eso que hay dos perfiles diferentes: uno para el desarrollo, cuando desea reconstruir rápida y frecuentemente, y otro para construir el programa final que le dará a un usuario que no se reconstruirá repetidamente y que se ejecutará tan rápido como posible.
Con proyectos simples, Cargo no proporciona mucho valor con solo usar rustc, pero demostrará su valor a medida que sus programas se vuelvan más complejos. Con proyectos complejos compuestos de múltiples cajas, es mucho más fácil dejar que Cargo coordine la construcción.
Aunque el proyecto hello_cargo es simple, ahora utilizamos gran parte de las herramientas reales que usará en el resto de su carrera en Rust. De hecho, para trabajar en cualquier proyecto existente, puede usar los siguientes comandos para verificar el código usando Git, cambiar al directorio de ese proyecto y compilar:
$ git clone someurl.com/someproject
$ cd someproject
$ cargo buildm
Y por este post, demasiado...
Dejo link:
https://doc.rust-lang.org/book
Suscribirse a:
Entradas (Atom)