TypeError: cannot pickle '_asyncio.Future' object

I am making a face recognition attendance system using python, whenever a request comes to WebSocket it opens a new camera in a new process using multiprocessing. Every thing works fine but when it comes to send message from process created with multiprocessing, I get an error (TypeError: cannot pickle ‘_asyncio.Future’ object) (COMPLETE ERROR IS GIVEN BELOW), The error “Can’t pickle local object” occurs because the Process class from the multiprocessing module requires the arguments passed to its target function to be picklable. Pickling is the process of converting a Python object into a byte stream so that it can be stored on disk or transmitted over a network. In my code, I’m passing the websocket object as an argument to the process_camera function, which is intended to be executed in a separate process. However, the websocket object is an instance of a class that is not picklable, meaning it cannot be serialized into a byte stream. This is because the websocket object contains references to underlying socket connections and other resources that cannot be serialized.

Any idea how I can send messages from multiple processes to the other side.

Extra Information: I’m using electron (a framework which is used to make cross-platform desktop applications with only HTML, CSS and JS.) with python and I am using websockets as a medium of communication between them. Each time the user wants to open the camera from the front-end, a request using websockets goes to python to open the camera in a separate process and start face recognition, I want to get responses from those camera processes but I’m getting errors.

My minimal code with all libraries I used:

import asyncio
import sqlite3
import pickle
import face_recognition
import cv2
import time
import numpy as np
import websockets
import json
from multiprocessing import Process


def process_camera(id, camera_port, websocket):
    websocket.send({"id": id, "camera": camera_port})
   
async def start_server(websocket, path):
    try:
        # Get the JSON data from the WebSocket connection
        async for message in websocket:
            data = json.loads(message)
            if data:
                # Extract the subject ID from the JSON data
                subject_id = data.get('subject_id')
                if subject_id == 1:
                    camera_port = 0
                else:
                    camera_port = 1

                # Start camera capture in a separate process
                p = Process(target=process_camera, args=(subject_id, camera_port, websocket))
                p.start()

    except websockets.exceptions.ConnectionClosedOK:
        print("Client connection closed")


async def main():
    async with websockets.serve(start_server, "localhost", 8765):
        await asyncio.Future()  # Keep the server running indefinitely


if __name__ == "__main__":
    asyncio.run(main())

ERROR:

connection handler failed
Traceback (most recent call last):
  File "C:\Users\Abdul Rafey\AppData\Local\Programs\Python\Python38\lib\site-packages\websockets\legacy\server.py", line 236, in handler     
    await self.ws_handler(self)
  File "C:\Users\Abdul Rafey\AppData\Local\Programs\Python\Python38\lib\site-packages\websockets\legacy\server.py", line 1175, in _ws_handler
    return await cast(
  File "c:/Users/Abdul Rafey/OneDrive/Desktop/electron app/electron-quick-start/python/camera.py", line 31, in start_server
    p.start()
  File "C:\Users\Abdul Rafey\AppData\Local\Programs\Python\Python38\lib\multiprocessing\process.py", line 121, in start
    self._popen = self._Popen(self)
  File "C:\Users\Abdul Rafey\AppData\Local\Programs\Python\Python38\lib\multiprocessing\context.py", line 224, in _Popen
    return _default_context.get_context().Process._Popen(process_obj)
  File "C:\Users\Abdul Rafey\AppData\Local\Programs\Python\Python38\lib\multiprocessing\context.py", line 327, in _Popen
    return Popen(process_obj)
  File "C:\Users\Abdul Rafey\AppData\Local\Programs\Python\Python38\lib\multiprocessing\popen_spawn_win32.py", line 93, in __init__
    reduction.dump(process_obj, to_child)
  File "C:\Users\Abdul Rafey\AppData\Local\Programs\Python\Python38\lib\multiprocessing\reduction.py", line 60, in dump
    ForkingPickler(file, protocol).dump(obj)
TypeError: cannot pickle '_asyncio.Future' object
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Users\Abdul Rafey\AppData\Local\Programs\Python\Python38\lib\multiprocessing\spawn.py", line 107, in spawn_main
    new_handle = reduction.duplicate(pipe_handle,
  File "C:\Users\Abdul Rafey\AppData\Local\Programs\Python\Python38\lib\multiprocessing\reduction.py", line 79, in duplicate
    return _winapi.DuplicateHandle(
OSError: [WinError 6] The handle is invalid

Your analysis is exactly correct. Pickling doesn’t magically send an object across; it sends a stream of bytes, which are used at the other end to construct an equivalent object. (It’s like faxing a document - although I doubt most people here have ever used such ancient technology.) There ARE ways to send sockets to other processes, but you’d then be responsible for sending all of the additional state (any buffered text, etc) to the other process.

But there’s a really REALLY easy solution here. Just don’t use multiprocessing for your websockets! Okay, I say that as if that’s trivially simple, but in reality, it’s actually not that hard. Run your main app purely as a single-threaded asyncio-based socket server; its entire job is to broker data between the different connections. Then - if you need to - you can have a subprocess that is solely about reading from the camera. I say “if you need to”, because it’s entirely possible that this, too, could be simply another task within the same application, which would save you a LOT of trouble. But if you do need that to be separate, its job would be to read from the camera and produce messages that get delivered to the main app (probably via a pipe - you could write them to STDOUT and have the main process read those) for subsequent delivery via websocket.

I do wonder, though, what the advantage of Python is in this at all. Web browsers are able to directly request permission to use cameras, so what is Python adding to the mix? My first thought was multiplexing (that is, a single Python program opens the webcam and reads from it, and then sends that data to multiple Electron front ends); but if that’s the case, it would make far more sense to keep it in a single asyncio-based process, with a task for reading from the webcam, a task for each websocket, and easy intra-process communication (far less hassle than inter-process communication). Or is there something else? I’m definitely curious here.

Anyway, hope that helps. I’ve worked a lot with websockets and I think they’re a spectacular tool, so hopefully this all works out well for you.

I am trying to make a face recognition attendance system for schools. As in schools, multiple classes run parallelly, so I need to access multiple cameras at the same time to run face recognition algorithms and record attendance. I used multiprocessing so I will start each camera in a new process and use my CPU completely. I thought this way I can utilize my PC resource efficiency and will see a significant disease in lag when multiple cameras start. I was previously using Flask for communication but then came to know that websockets are used for bi-directional communication and is also light weight compared to Flask. After this I modified my code and used websockets with asyncio. I have used inter-process communication earlier for communication, but I realized whenever I print something in python and also use flush after it, sometimes I don’t get responses (or may be not on time) using STDOUT in electron from python.

I’m new to websockets and asyncio and don’t know to much about them.
The whole point is,

  • I want my code to run fast efficiency and use full PC resources(CPU) if available (I may add use of GPU later when I use Tenserflow for deep learning).
  • I want a proper bi-directional communication between python and electron. For now, I only want to send message when a camera is turned off (or a process finished) and want to return error if any exception happened while doing face recognition. But may be in future I wish to send more data of specific type as my application grows.

My complete python code is on Github.
As I explained what I’m building so if know you may suggest libraries better than the ones I’m using or the ones which can make my application more efficient and feature rich.
I appreciate if you show me solution practically by modifying my code.

Ah, okay. Kinda the inverse of my initial guess: instead of getting one camera and splitting it between clients, you’re getting multiple cameras and processing them separately. Same thing though: you can have a “worker” process that knows nothing about the websockets, and a “communication” process that is managing all of the Flask requests, including websockets. (There’ll be multiple copies of the worker process but they’ll all be doing the same work, just on different webcams.)

You’ll need to plan out the protocol between those two processes and how a signal will be sent from the camera process all the way back through to Electron. I would recommend looking into pipes; the comms process can juggle a huge number of them without much effort.

No probs. Short summary: Websockets let your Python app and your Electron app communicate bidirectionally, using messages, generally JSON. AsyncIO is Python’s way of having a single-threaded program juggle a ton of concurrent tasks, and it does a great job of handling I/O (as the name suggests), so that means sockets (including websockets and HTTP requests), pipes, files, network requests, and anything else that you can get on a file descriptor (eg inotify if you’re on Linux).

I think your selection of libraries is fine :slight_smile: Just going to have to figure out the parts where you control both ends. You see, the great part about controlling both ends is that you have complete flexibility to design how they communicate… the bad part is, you have complete flexibility, which means you have to think of everything instead of being forced into one path :smiley:

I’m unable to get what you are saying and hence unable to solve my problem, I’m a type of person who understand things with code examples.
EDITABLE PYTHON CODE LINK: Sign Up - Replit

If you need tutoring, I suggest you find someone and pay them for their time.

1 Like